From 74f039e36f265cb00ba3689dc7e7d2fb3c8b81af Mon Sep 17 00:00:00 2001 From: Niellune Date: Fri, 27 Mar 2026 23:41:40 +0200 Subject: [PATCH] Better frame sheduling for smoothness --- Makefile | 12 ++++++-- settings.txt | 6 ---- src/application.cpp | 68 ++++++++++++++++++++------------------------- src/application.h | 1 - src/interface.cpp | 6 +++- src/settings.h | 1 - 6 files changed, 45 insertions(+), 49 deletions(-) diff --git a/Makefile b/Makefile index 534cfd5..12e72cb 100644 --- a/Makefile +++ b/Makefile @@ -31,9 +31,17 @@ debug: LDFLAGS += -fsanitize=address -fno-omit-frame-pointer debug: TARGET := $(TARGET_NAME)-debug debug: prepare +ifeq ($(shell uname -s), Darwin) + # macOS / clang + PLATFORM_LDFLAGS := +else + # Linux / GCC (Pi or other) + PLATFORM_LDFLAGS := -Wl,--gc-sections -Wl,--as-needed +endif + release: BUILD_TYPE := release -release: CXXFLAGS := -O3 -ffast-math -march=native -fno-plt -fno-rtti -flto -fdata-sections -ffunction-sections -DNDEBUG -release: LDFLAGS += -O3 -ffast-math -march=native -Wl,--gc-sections -flto +release: CXXFLAGS := -O2 -ffast-math -march=native -fno-plt -fno-rtti -flto -fdata-sections -ffunction-sections -ffunction-sections -fomit-frame-pointer -fvisibility=hidden -pipe -DNDEBUG +release: LDFLAGS += -O2 -ffast-math -march=native -flto -Wl,-O1 $(PLATFORM_LDFLAGS) release: TARGET := $(TARGET_NAME) release: prepare diff --git a/settings.txt b/settings.txt index 1ae37d3..a5df215 100644 --- a/settings.txt +++ b/settings.txt @@ -14,12 +14,6 @@ # Requested image refresh rate #source-fps = 60 -# Application drawing target framerate. This can responsiveness. -# If the setting is lower than source-fps the framse will be dropped -# If the setting is not multiple of source-fps can still cause frame drops cause out-of-sync -# source images and drawing times -#fps = 60 - # Application window mode # 0 - windowed # 1 - fullscreen diff --git a/src/application.cpp b/src/application.cpp index d95efdf..a6b3ae2 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include #include "struct/video_buffer.h" #include "common/logger.h" @@ -313,21 +315,20 @@ void Application::loop() protocol.start(); log_v("Loop"); - Uint32 frameStart = SDL_GetTicks(); + std::chrono::steady_clock::time_point frameStart = std::chrono::steady_clock::now(); + int32_t frameTime = 0; + int32_t frameDelay = 0; + const int32_t frameTarget = Settings::sourceFps > 0 ? 1000000 / Settings::sourceFps : 1000000; AVFrame *frame = nullptr; - uint32_t frameid = 0; - uint32_t latestFrameid = 0; - uint32_t frameTargetTime = Settings::fps > 0 ? 1000 / Settings::fps : 1000; - uint32_t delay = 0; + uint32_t frameId = 0; uint32_t dropframes = 0; int skipEvents = 0; - int frameTime = 0; Uint32 debugLast = SDL_GetTicks(); int debugSpeed = 0; int debugLastCount = 0; while (_active) { - bool late = false; + bool newFrame = false; if (protocol.state() != _state.latestState) { @@ -347,29 +348,24 @@ void Application::loop() _state.latestState = protocol.state(); } - if (_state.latestState == PROTOCOL_STATUS_CONNECTED && _state.showVideo) + if (_state.latestState == PROTOCOL_STATUS_CONNECTED) { - delay = 0; - while (!_state.dirty && decoder.buffer.latestId() == latestFrameid && ++delay < frameTargetTime) + uint32_t latestFrameId = 0; + if (decoder.buffer.consume(&frame, &latestFrameId)) { - SDL_Delay(1); - } - - if (decoder.buffer.consume(&frame, &frameid)) - { - bool newFrame = frameid != latestFrameid; + newFrame = latestFrameId != frameId; if (newFrame || _state.dirty) { if (interface.render(frame)) { _state.frameRendered = true; _state.dirty = false; - if (latestFrameid > 0 && frameid - latestFrameid > 1) + if (frameId > 0 && latestFrameId - frameId > 1) { - dropframes += frameid - latestFrameid - 1; - log_d("Frame drop %d on %d total %d", frameid - latestFrameid - 1, frameid, dropframes); + dropframes += latestFrameId - frameId - 1; + log_d("Frame drop %d on %d total %d", latestFrameId - frameId - 1, latestFrameId, dropframes); } - latestFrameid = frameid; + frameId = latestFrameId; } } } @@ -383,7 +379,7 @@ void Application::loop() } } - if (!_state.frameRendered || !_state.showVideo) + if (!_state.frameRendered) { interface.drawHome(_state.dirty, _state.latestState, protocol.phoneName()); _state.dirty = false; @@ -393,8 +389,7 @@ void Application::loop() } else { - late = decoder.buffer.latestId() - latestFrameid > 1; - if (!late || ++skipEvents > Settings::eventsSkip) + if (newFrame || ++skipEvents > Settings::eventsSkip) { if (processFrameEvents(protocol.writeQueue, interface) && Settings::forceRedraw > 0) { @@ -415,16 +410,16 @@ void Application::loop() char debugBuffer[2048]; std::snprintf(debugBuffer, sizeof(debugBuffer), "%s\n" - "FRAME: %u / %u [%d] dropped: %d render: %dms / %dms\n" + "FRAME: %u / %u [%d] dropped: %d render: %uus / %uus\n" "USB: %s ~%dKB/s\n" "BUFF: video [%u] audio[main %u aux %u] out [%u]", status().c_str(), - latestFrameid, + frameId, decoder.buffer.latestId(), - decoder.buffer.latestId() - latestFrameid, + decoder.buffer.latestId() - frameId, dropframes, frameTime, - delay, + frameDelay, protocol.status().c_str(), debugSpeed, protocol.videoStream.count(), @@ -434,19 +429,16 @@ void Application::loop() interface.debug(debugBuffer); } - if (_active && !Settings::vsync) + if (_active && !Settings::vsync && !_state.dirty) { - Uint32 frameEnd = SDL_GetTicks(); - frameTime = frameEnd - frameStart; - int frameDelay = frameTargetTime - frameTime; - if (frameDelay <= 0 || decoder.buffer.latestId() - latestFrameid > 1) + std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); + frameTime = (int32_t)std::chrono::duration_cast(now - frameStart).count(); + frameDelay = (frameTarget - frameTime) * ((decoder.buffer.latestId() == frameId) ? 1.0 : 0.9); + frameStart = now; + if (frameDelay > 0) { - frameStart = frameEnd; - } - else - { - SDL_Delay(frameDelay); - frameStart += frameDelay; + std::this_thread::sleep_for(std::chrono::microseconds(frameDelay)); + frameStart += std::chrono::microseconds(frameDelay); } } } diff --git a/src/application.h b/src/application.h index 64571f0..9438240 100644 --- a/src/application.h +++ b/src/application.h @@ -24,7 +24,6 @@ private: bool dirty = false; bool frameRendered = false; int requestFrame = 0; - bool showVideo = true; bool fullscreen = false; bool mouseDown = false; int8_t latestState = PROTOCOL_STATUS_UNKNOWN; diff --git a/src/interface.cpp b/src/interface.cpp index 3315eda..bce80cc 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -77,8 +77,12 @@ bool Interface::drawHome(bool force, int state, std::string name) drawText = true; if (state == PROTOCOL_STATUS_CONNECTED) - if (_textStatus.prepare(_renderer, "Connecting to "+name, color3)) + { + if(name.length()>0) + name = " to "+name; + if (_textStatus.prepare(_renderer, "Connecting"+name, color3)) drawText = true; + } if (drawText) _textStatus.draw(_renderer, (width - _textStatus.width) / 2, height * 0.85 - _textStatus.height); diff --git a/src/settings.h b/src/settings.h index 309772f..b287437 100644 --- a/src/settings.h +++ b/src/settings.h @@ -17,7 +17,6 @@ public: static inline Setting width{"width", 1024}; static inline Setting height{"height", 576}; static inline Setting sourceFps{"source-fps", 60}; - static inline Setting fps{"fps", 60}; static inline Setting screenMode{"window-mode", 0}; static inline Setting cursor{"cursor", false}; static inline Setting loglevel{"log-level", 2};