perf: sync native danmaku with screen refresh
This commit is contained in:
@@ -12,7 +12,9 @@
|
||||
#include <QRectF>
|
||||
#include <QResizeEvent>
|
||||
#include <QScreen>
|
||||
#include <QShowEvent>
|
||||
#include <QTimer>
|
||||
#include <QWindow>
|
||||
#include <QtGlobal>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -26,7 +28,9 @@ constexpr qreal kReferenceHeight = 1080.0;
|
||||
constexpr qreal kTopMargin = 24.0;
|
||||
constexpr qreal kBottomMargin = 48.0;
|
||||
constexpr int kResizeRebuildDebounceMs = 48;
|
||||
constexpr int kDefaultFrameIntervalMs = 8;
|
||||
constexpr int kFallbackFrameIntervalMs = 16;
|
||||
constexpr int kMinFrameIntervalMs = 4;
|
||||
constexpr int kMaxFrameIntervalMs = 33;
|
||||
constexpr qreal kScrollStartPadding = 32.0;
|
||||
constexpr qreal kScrollEndPadding = 48.0;
|
||||
constexpr qreal kScrollLaneGapPadding = 96.0;
|
||||
@@ -150,7 +154,7 @@ NativeDanmakuOverlay::NativeDanmakuOverlay(MpvController *controller,
|
||||
|
||||
m_frameTimer = new QTimer(this);
|
||||
m_frameTimer->setTimerType(Qt::PreciseTimer);
|
||||
m_frameTimer->setInterval(kDefaultFrameIntervalMs);
|
||||
m_frameTimer->setInterval(kFallbackFrameIntervalMs);
|
||||
connect(m_frameTimer, &QTimer::timeout, this, [this]() {
|
||||
const qint64 positionMs = currentPositionMs();
|
||||
if (m_lastResolvedPositionMs < 0 || positionMs < m_lastResolvedPositionMs ||
|
||||
@@ -168,6 +172,8 @@ NativeDanmakuOverlay::NativeDanmakuOverlay(MpvController *controller,
|
||||
connect(m_scheduleRebuildTimer, &QTimer::timeout, this,
|
||||
&NativeDanmakuOverlay::rebuildScheduleNow);
|
||||
|
||||
updateScreenRefreshBinding();
|
||||
|
||||
if (!m_controller) {
|
||||
return;
|
||||
}
|
||||
@@ -331,6 +337,13 @@ void NativeDanmakuOverlay::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
requestScheduleRebuild(false, false);
|
||||
updateScreenRefreshBinding();
|
||||
}
|
||||
|
||||
void NativeDanmakuOverlay::showEvent(QShowEvent *event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
updateScreenRefreshBinding();
|
||||
}
|
||||
|
||||
void NativeDanmakuOverlay::rebuildSchedule()
|
||||
@@ -653,20 +666,76 @@ void NativeDanmakuOverlay::syncFrameTimer()
|
||||
|
||||
int NativeDanmakuOverlay::targetFrameIntervalMs() const
|
||||
{
|
||||
const QScreen *targetScreen = screen();
|
||||
if (!targetScreen && window()) {
|
||||
targetScreen = window()->screen();
|
||||
}
|
||||
|
||||
const qreal refreshRate = targetScreen ? targetScreen->refreshRate() : 0.0;
|
||||
const QScreen *screen = targetScreen();
|
||||
const qreal refreshRate = screen ? screen->refreshRate() : 0.0;
|
||||
if (refreshRate <= 0.0) {
|
||||
return kDefaultFrameIntervalMs;
|
||||
return kFallbackFrameIntervalMs;
|
||||
}
|
||||
|
||||
const qreal desiredRefreshRate = std::max<qreal>(120.0, refreshRate);
|
||||
return qBound(4,
|
||||
static_cast<int>(std::lround(1000.0 / desiredRefreshRate)),
|
||||
kDefaultFrameIntervalMs);
|
||||
return qBound(kMinFrameIntervalMs,
|
||||
static_cast<int>(std::lround(1000.0 / refreshRate)),
|
||||
kMaxFrameIntervalMs);
|
||||
}
|
||||
|
||||
QScreen *NativeDanmakuOverlay::targetScreen() const
|
||||
{
|
||||
if (QScreen *widgetScreen = screen()) {
|
||||
return widgetScreen;
|
||||
}
|
||||
if (const QWidget *topLevel = window()) {
|
||||
if (QWindow *handle = topLevel->windowHandle()) {
|
||||
if (QScreen *windowScreen = handle->screen()) {
|
||||
return windowScreen;
|
||||
}
|
||||
}
|
||||
if (QScreen *windowScreen = topLevel->screen()) {
|
||||
return windowScreen;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NativeDanmakuOverlay::updateScreenRefreshBinding()
|
||||
{
|
||||
QWindow *currentWindow = nullptr;
|
||||
if (QWidget *topLevel = window()) {
|
||||
currentWindow = topLevel->windowHandle();
|
||||
}
|
||||
|
||||
if (m_observedWindow != currentWindow) {
|
||||
if (m_windowScreenConnection) {
|
||||
QObject::disconnect(m_windowScreenConnection);
|
||||
m_windowScreenConnection = {};
|
||||
}
|
||||
m_observedWindow = currentWindow;
|
||||
if (m_observedWindow) {
|
||||
m_windowScreenConnection =
|
||||
connect(m_observedWindow, &QWindow::screenChanged, this,
|
||||
[this](QScreen *) {
|
||||
updateScreenRefreshBinding();
|
||||
syncFrameTimer();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
QScreen *currentScreen = targetScreen();
|
||||
if (m_observedScreen == currentScreen) {
|
||||
syncFrameTimer();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_screenRefreshConnection) {
|
||||
QObject::disconnect(m_screenRefreshConnection);
|
||||
m_screenRefreshConnection = {};
|
||||
}
|
||||
m_observedScreen = currentScreen;
|
||||
if (m_observedScreen) {
|
||||
m_screenRefreshConnection =
|
||||
connect(m_observedScreen, &QScreen::refreshRateChanged, this,
|
||||
[this](qreal) { syncFrameTimer(); });
|
||||
}
|
||||
|
||||
syncFrameTimer();
|
||||
}
|
||||
|
||||
void NativeDanmakuOverlay::refreshBasePosition(qint64 positionMs)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QHash>
|
||||
#include <QMetaObject>
|
||||
#include <QPixmap>
|
||||
#include <QPointer>
|
||||
#include <QSize>
|
||||
@@ -14,9 +15,12 @@
|
||||
class MpvController;
|
||||
class QPaintEvent;
|
||||
class QResizeEvent;
|
||||
class QScreen;
|
||||
class QShowEvent;
|
||||
class QTimer;
|
||||
class QVariant;
|
||||
class QRectF;
|
||||
class QWindow;
|
||||
|
||||
class NativeDanmakuOverlay : public QWidget
|
||||
{
|
||||
@@ -35,6 +39,7 @@ public:
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
private:
|
||||
enum class ItemType {
|
||||
@@ -66,6 +71,8 @@ private:
|
||||
void clearScheduledState(bool clearSpriteCache = false);
|
||||
void syncFrameTimer();
|
||||
int targetFrameIntervalMs() const;
|
||||
QScreen *targetScreen() const;
|
||||
void updateScreenRefreshBinding();
|
||||
void refreshBasePosition(qint64 positionMs);
|
||||
qreal currentPositionMsPrecise() const;
|
||||
qint64 currentPositionMs() const;
|
||||
@@ -80,6 +87,10 @@ private:
|
||||
QPointer<MpvController> m_controller;
|
||||
QTimer *m_frameTimer = nullptr;
|
||||
QTimer *m_scheduleRebuildTimer = nullptr;
|
||||
QPointer<QWindow> m_observedWindow;
|
||||
QPointer<QScreen> m_observedScreen;
|
||||
QMetaObject::Connection m_windowScreenConnection;
|
||||
QMetaObject::Connection m_screenRefreshConnection;
|
||||
QElapsedTimer m_positionClock;
|
||||
QList<DanmakuComment> m_comments;
|
||||
QList<DanmakuComment> m_sortedComments;
|
||||
|
||||
Reference in New Issue
Block a user