mirror of
https://github.com/niellun/FastCarPlay.git
synced 2026-06-07 09:38:25 +02:00
Better frame sheduling for smoothness
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+30
-38
@@ -3,6 +3,8 @@
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#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<std::chrono::microseconds>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
+5
-1
@@ -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);
|
||||
|
||||
@@ -17,7 +17,6 @@ public:
|
||||
static inline Setting<int> width{"width", 1024};
|
||||
static inline Setting<int> height{"height", 576};
|
||||
static inline Setting<int> sourceFps{"source-fps", 60};
|
||||
static inline Setting<int> fps{"fps", 60};
|
||||
static inline Setting<int> screenMode{"window-mode", 0};
|
||||
static inline Setting<bool> cursor{"cursor", false};
|
||||
static inline Setting<int> loglevel{"log-level", 2};
|
||||
|
||||
Reference in New Issue
Block a user