mirror of
https://github.com/niellun/FastCarPlay.git
synced 2026-09-19 09:02:14 +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: TARGET := $(TARGET_NAME)-debug
|
||||||
debug: prepare
|
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: BUILD_TYPE := release
|
||||||
release: CXXFLAGS := -O3 -ffast-math -march=native -fno-plt -fno-rtti -flto -fdata-sections -ffunction-sections -DNDEBUG
|
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 += -O3 -ffast-math -march=native -Wl,--gc-sections -flto
|
release: LDFLAGS += -O2 -ffast-math -march=native -flto -Wl,-O1 $(PLATFORM_LDFLAGS)
|
||||||
release: TARGET := $(TARGET_NAME)
|
release: TARGET := $(TARGET_NAME)
|
||||||
release: prepare
|
release: prepare
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,6 @@
|
|||||||
# Requested image refresh rate
|
# Requested image refresh rate
|
||||||
#source-fps = 60
|
#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
|
# Application window mode
|
||||||
# 0 - windowed
|
# 0 - windowed
|
||||||
# 1 - fullscreen
|
# 1 - fullscreen
|
||||||
|
|||||||
+30
-38
@@ -3,6 +3,8 @@
|
|||||||
#include <SDL2/SDL_ttf.h>
|
#include <SDL2/SDL_ttf.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "struct/video_buffer.h"
|
#include "struct/video_buffer.h"
|
||||||
#include "common/logger.h"
|
#include "common/logger.h"
|
||||||
@@ -313,21 +315,20 @@ void Application::loop()
|
|||||||
protocol.start();
|
protocol.start();
|
||||||
|
|
||||||
log_v("Loop");
|
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;
|
AVFrame *frame = nullptr;
|
||||||
uint32_t frameid = 0;
|
uint32_t frameId = 0;
|
||||||
uint32_t latestFrameid = 0;
|
|
||||||
uint32_t frameTargetTime = Settings::fps > 0 ? 1000 / Settings::fps : 1000;
|
|
||||||
uint32_t delay = 0;
|
|
||||||
uint32_t dropframes = 0;
|
uint32_t dropframes = 0;
|
||||||
int skipEvents = 0;
|
int skipEvents = 0;
|
||||||
int frameTime = 0;
|
|
||||||
Uint32 debugLast = SDL_GetTicks();
|
Uint32 debugLast = SDL_GetTicks();
|
||||||
int debugSpeed = 0;
|
int debugSpeed = 0;
|
||||||
int debugLastCount = 0;
|
int debugLastCount = 0;
|
||||||
while (_active)
|
while (_active)
|
||||||
{
|
{
|
||||||
bool late = false;
|
bool newFrame = false;
|
||||||
|
|
||||||
if (protocol.state() != _state.latestState)
|
if (protocol.state() != _state.latestState)
|
||||||
{
|
{
|
||||||
@@ -347,29 +348,24 @@ void Application::loop()
|
|||||||
_state.latestState = protocol.state();
|
_state.latestState = protocol.state();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_state.latestState == PROTOCOL_STATUS_CONNECTED && _state.showVideo)
|
if (_state.latestState == PROTOCOL_STATUS_CONNECTED)
|
||||||
{
|
{
|
||||||
delay = 0;
|
uint32_t latestFrameId = 0;
|
||||||
while (!_state.dirty && decoder.buffer.latestId() == latestFrameid && ++delay < frameTargetTime)
|
if (decoder.buffer.consume(&frame, &latestFrameId))
|
||||||
{
|
{
|
||||||
SDL_Delay(1);
|
newFrame = latestFrameId != frameId;
|
||||||
}
|
|
||||||
|
|
||||||
if (decoder.buffer.consume(&frame, &frameid))
|
|
||||||
{
|
|
||||||
bool newFrame = frameid != latestFrameid;
|
|
||||||
if (newFrame || _state.dirty)
|
if (newFrame || _state.dirty)
|
||||||
{
|
{
|
||||||
if (interface.render(frame))
|
if (interface.render(frame))
|
||||||
{
|
{
|
||||||
_state.frameRendered = true;
|
_state.frameRendered = true;
|
||||||
_state.dirty = false;
|
_state.dirty = false;
|
||||||
if (latestFrameid > 0 && frameid - latestFrameid > 1)
|
if (frameId > 0 && latestFrameId - frameId > 1)
|
||||||
{
|
{
|
||||||
dropframes += frameid - latestFrameid - 1;
|
dropframes += latestFrameId - frameId - 1;
|
||||||
log_d("Frame drop %d on %d total %d", frameid - latestFrameid - 1, frameid, dropframes);
|
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());
|
interface.drawHome(_state.dirty, _state.latestState, protocol.phoneName());
|
||||||
_state.dirty = false;
|
_state.dirty = false;
|
||||||
@@ -393,8 +389,7 @@ void Application::loop()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
late = decoder.buffer.latestId() - latestFrameid > 1;
|
if (newFrame || ++skipEvents > Settings::eventsSkip)
|
||||||
if (!late || ++skipEvents > Settings::eventsSkip)
|
|
||||||
{
|
{
|
||||||
if (processFrameEvents(protocol.writeQueue, interface) && Settings::forceRedraw > 0)
|
if (processFrameEvents(protocol.writeQueue, interface) && Settings::forceRedraw > 0)
|
||||||
{
|
{
|
||||||
@@ -415,16 +410,16 @@ void Application::loop()
|
|||||||
char debugBuffer[2048];
|
char debugBuffer[2048];
|
||||||
std::snprintf(debugBuffer, sizeof(debugBuffer),
|
std::snprintf(debugBuffer, sizeof(debugBuffer),
|
||||||
"%s\n"
|
"%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"
|
"USB: %s ~%dKB/s\n"
|
||||||
"BUFF: video [%u] audio[main %u aux %u] out [%u]",
|
"BUFF: video [%u] audio[main %u aux %u] out [%u]",
|
||||||
status().c_str(),
|
status().c_str(),
|
||||||
latestFrameid,
|
frameId,
|
||||||
decoder.buffer.latestId(),
|
decoder.buffer.latestId(),
|
||||||
decoder.buffer.latestId() - latestFrameid,
|
decoder.buffer.latestId() - frameId,
|
||||||
dropframes,
|
dropframes,
|
||||||
frameTime,
|
frameTime,
|
||||||
delay,
|
frameDelay,
|
||||||
protocol.status().c_str(),
|
protocol.status().c_str(),
|
||||||
debugSpeed,
|
debugSpeed,
|
||||||
protocol.videoStream.count(),
|
protocol.videoStream.count(),
|
||||||
@@ -434,19 +429,16 @@ void Application::loop()
|
|||||||
interface.debug(debugBuffer);
|
interface.debug(debugBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_active && !Settings::vsync)
|
if (_active && !Settings::vsync && !_state.dirty)
|
||||||
{
|
{
|
||||||
Uint32 frameEnd = SDL_GetTicks();
|
std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
|
||||||
frameTime = frameEnd - frameStart;
|
frameTime = (int32_t)std::chrono::duration_cast<std::chrono::microseconds>(now - frameStart).count();
|
||||||
int frameDelay = frameTargetTime - frameTime;
|
frameDelay = (frameTarget - frameTime) * ((decoder.buffer.latestId() == frameId) ? 1.0 : 0.9);
|
||||||
if (frameDelay <= 0 || decoder.buffer.latestId() - latestFrameid > 1)
|
frameStart = now;
|
||||||
|
if (frameDelay > 0)
|
||||||
{
|
{
|
||||||
frameStart = frameEnd;
|
std::this_thread::sleep_for(std::chrono::microseconds(frameDelay));
|
||||||
}
|
frameStart += std::chrono::microseconds(frameDelay);
|
||||||
else
|
|
||||||
{
|
|
||||||
SDL_Delay(frameDelay);
|
|
||||||
frameStart += frameDelay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ private:
|
|||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
bool frameRendered = false;
|
bool frameRendered = false;
|
||||||
int requestFrame = 0;
|
int requestFrame = 0;
|
||||||
bool showVideo = true;
|
|
||||||
bool fullscreen = false;
|
bool fullscreen = false;
|
||||||
bool mouseDown = false;
|
bool mouseDown = false;
|
||||||
int8_t latestState = PROTOCOL_STATUS_UNKNOWN;
|
int8_t latestState = PROTOCOL_STATUS_UNKNOWN;
|
||||||
|
|||||||
+5
-1
@@ -77,8 +77,12 @@ bool Interface::drawHome(bool force, int state, std::string name)
|
|||||||
drawText = true;
|
drawText = true;
|
||||||
|
|
||||||
if (state == PROTOCOL_STATUS_CONNECTED)
|
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;
|
drawText = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (drawText)
|
if (drawText)
|
||||||
_textStatus.draw(_renderer, (width - _textStatus.width) / 2, height * 0.85 - _textStatus.height);
|
_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> width{"width", 1024};
|
||||||
static inline Setting<int> height{"height", 576};
|
static inline Setting<int> height{"height", 576};
|
||||||
static inline Setting<int> sourceFps{"source-fps", 60};
|
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<int> screenMode{"window-mode", 0};
|
||||||
static inline Setting<bool> cursor{"cursor", false};
|
static inline Setting<bool> cursor{"cursor", false};
|
||||||
static inline Setting<int> loglevel{"log-level", 2};
|
static inline Setting<int> loglevel{"log-level", 2};
|
||||||
|
|||||||
Reference in New Issue
Block a user