From 929b613ab8b6c7d2bd389cf8a38bd2da1821a186 Mon Sep 17 00:00:00 2001 From: Niellune Date: Tue, 24 Mar 2026 18:08:01 +0200 Subject: [PATCH] Thread priority, better debug overlay --- src/application.cpp | 71 +++++++++++++++++-- src/application.h | 1 + src/common/threading.h | 109 ++++++++++++++++++++++++++--- src/interface.cpp | 22 +++++- src/protocol/connection_reader.cpp | 1 + 5 files changed, 187 insertions(+), 17 deletions(-) diff --git a/src/application.cpp b/src/application.cpp index 1bc73cd..ebca340 100644 --- a/src/application.cpp +++ b/src/application.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "struct/video_buffer.h" #include "common/logger.h" @@ -393,7 +394,7 @@ void Application::loop() else { late = decoder.buffer.latestId() - latestFrameid > 1; - if(!late || ++skipEvents > Settings::eventsSkip) + if (!late || ++skipEvents > Settings::eventsSkip) { if (processFrameEvents(protocol.writeQueue, interface) && Settings::forceRedraw > 0) { @@ -405,18 +406,21 @@ void Application::loop() if (_debug) { - char debugBuffer[256]; + char debugBuffer[512]; std::snprintf(debugBuffer, sizeof(debugBuffer), - "FRAME: %u / %u [%d] droped %d\n" - "TIME: %d delay %d\n" + "%s\n" + "FRAME: %u / %u [%d] dropped: %d render: %dms / %dms\n" "VIDEO: %u\n" "AUDIO-MAIN: %u\n" "AUDIO-AUX: %u\n" "OUT: %u", + status().c_str(), latestFrameid, decoder.buffer.latestId(), - decoder.buffer.latestId() - latestFrameid, dropframes, - frameTime, delay, + decoder.buffer.latestId() - latestFrameid, + dropframes, + frameTime, + delay, protocol.videoStream.count(), protocol.audioStreamMain.count(), protocol.audioStreamAux.count(), @@ -444,3 +448,58 @@ void Application::loop() if (!Settings::isHeadless()) SDL_HideWindow(_window); } + +const std::string Application::status() const +{ + std::ostringstream out; + + SDL_version compiled{}; + SDL_VERSION(&compiled); + SDL_version linked{}; + SDL_GetVersion(&linked); + + out << "SDL: v" + << static_cast(compiled.major) << '.' + << static_cast(compiled.minor) << '.' + << static_cast(compiled.patch) << " " + << SDL_GetCurrentVideoDriver(); + + SDL_Window *window = SDL_GetKeyboardFocus(); + if (window) + { + int width = 0; + int height = 0; + SDL_GetWindowSize(window, &width, &height); + out << " " << width << 'x' << height; + SDL_Renderer *renderer = SDL_GetRenderer(window); + if (renderer) + { + SDL_RendererInfo info{}; + if (SDL_GetRendererInfo(renderer, &info) == 0) + { + out << " " << info.name + << ((info.flags & SDL_RENDERER_ACCELERATED) != 0?" accelerated":"") + << ((info.flags & SDL_RENDERER_PRESENTVSYNC) != 0?" vsync":""); + } + } + } + out << " " << SDL_GetCurrentAudioDriver(); + + int displayIndex = SDL_GetWindowDisplayIndex(window); + if (displayIndex >= 0) + { + out << "\nSCREEN:"; + SDL_Rect bounds{}; + SDL_DisplayMode mode{}; + SDL_GetDisplayBounds(displayIndex, &bounds); + if (SDL_GetCurrentDisplayMode(displayIndex, &mode) == 0) + { + out << " [" << displayIndex << "] " + << bounds.w << 'x' << bounds.h + << '@' << mode.refresh_rate + << " " << SDL_GetPixelFormatName(mode.format); + } + } + + return out.str(); +} diff --git a/src/application.h b/src/application.h index 95e6d7f..2b82a72 100644 --- a/src/application.h +++ b/src/application.h @@ -35,6 +35,7 @@ private: int processKey(SDL_Keysym key); bool processSystemEvent(const SDL_Event &e); bool processFrameEvents(AtomicQueue &queue, Renderer &renderer); + const std::string status() const; void loop(); diff --git a/src/common/threading.h b/src/common/threading.h index fa9d7de..93638e1 100644 --- a/src/common/threading.h +++ b/src/common/threading.h @@ -1,23 +1,114 @@ #ifndef SRC_HELPER_THREADING #define SRC_HELPER_THREADING +#include + #if defined(__linux__) || defined(__APPLE__) -#include + #include #endif -extern "C" -{ -#include -} +#if defined(__linux__) + #include +#elif defined(_WIN32) + #include +#endif -inline void setThreadName(const char *name) +inline void setThreadName(const char* name) { #if defined(__linux__) - pthread_setname_np(pthread_self(), name); // Linux: OK (limit 16 chars including null) + pthread_setname_np(pthread_self(), name); + #elif defined(__APPLE__) - pthread_setname_np(name); // macOS: only current thread, OK + pthread_setname_np(name); + +#elif defined(_WIN32) + // Windows 10+ + using SetThreadDescriptionFunc = HRESULT(WINAPI*)(HANDLE, PCWSTR); + static auto func = (SetThreadDescriptionFunc) + GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetThreadDescription"); + + if (func) + { + wchar_t wname[64]; + mbstowcs(wname, name, 63); + wname[63] = 0; + func(GetCurrentThread(), wname); + } + #else - (void)name; // suppress unused warning + (void)name; +#endif +} + +enum class ThreadPriority +{ + Low, + Normal, + High, + Realtime +}; + +inline bool setThreadPriority(ThreadPriority prio) +{ +#if defined(__linux__) + + int policy = SCHED_OTHER; + sched_param param{}; + + switch (prio) + { + case ThreadPriority::Low: + case ThreadPriority::Normal: + policy = SCHED_OTHER; + param.sched_priority = 0; + break; + + case ThreadPriority::High: + policy = SCHED_FIFO; + param.sched_priority = 10; + break; + + case ThreadPriority::Realtime: + policy = SCHED_FIFO; + param.sched_priority = 50; + break; + } + + return pthread_setschedparam(pthread_self(), policy, ¶m) == 0; + +#elif defined(__APPLE__) + + qos_class_t qos = QOS_CLASS_DEFAULT; + + switch (prio) + { + case ThreadPriority::Low: qos = QOS_CLASS_BACKGROUND; break; + case ThreadPriority::Normal: qos = QOS_CLASS_DEFAULT; break; + case ThreadPriority::High: qos = QOS_CLASS_USER_INITIATED; break; + case ThreadPriority::Realtime: qos = QOS_CLASS_USER_INTERACTIVE; break; + } + + return pthread_set_qos_class_self_np(qos, 0) == 0; + +#elif defined(_WIN32) + + int winPrio = THREAD_PRIORITY_NORMAL; + + switch (prio) + { + case ThreadPriority::Low: winPrio = THREAD_PRIORITY_BELOW_NORMAL; break; + case ThreadPriority::Normal: winPrio = THREAD_PRIORITY_NORMAL; break; + case ThreadPriority::High: winPrio = THREAD_PRIORITY_ABOVE_NORMAL; break; + case ThreadPriority::Realtime: winPrio = THREAD_PRIORITY_TIME_CRITICAL; break; + } + + return SetThreadPriority(GetCurrentThread(), winPrio); + +#else + + (void)prio; + return false; + #endif } diff --git a/src/interface.cpp b/src/interface.cpp index 60127b0..67b2f1d 100644 --- a/src/interface.cpp +++ b/src/interface.cpp @@ -24,7 +24,7 @@ Interface::~Interface() bool Interface::render(AVFrame *frame) { - if(!frame) + if (!frame) return false; if (_render == nullptr || frame->width != _textureWidth || frame->height != _textureHeight) @@ -91,7 +91,14 @@ void Interface::drawDebug() constexpr int padding = 8; constexpr int lineSpacing = 2; - const SDL_Color debugColor = {255, 0, 255, 255}; + const SDL_Color debugColor = {0, 255, 255, 255}; + SDL_BlendMode previousBlendMode; + Uint8 previousR, previousG, previousB, previousA; + SDL_GetRenderDrawBlendMode(_renderer, &previousBlendMode); + SDL_GetRenderDrawColor(_renderer, &previousR, &previousG, &previousB, &previousA); + SDL_SetRenderDrawBlendMode(_renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(_renderer, 0, 0, 0, 150); + size_t lineStart = 0; int y = padding; @@ -100,7 +107,15 @@ void Interface::drawDebug() size_t lineEnd = _debugText.find('\n', lineStart); std::string line = _debugText.substr(lineStart, lineEnd - lineStart); if (_textDebug.prepare(_renderer, line, debugColor)) + { + SDL_Rect backgroundRect = { + 0, + y, + static_cast(_textDebug.width * Settings::aspectCorrection) + padding * 2, + _textDebug.height}; + SDL_RenderFillRect(_renderer, &backgroundRect); _textDebug.draw(_renderer, padding, y); + } y += _textDebug.height + lineSpacing; if (lineEnd == std::string::npos) @@ -108,4 +123,7 @@ void Interface::drawDebug() lineStart = lineEnd + 1; } + + SDL_SetRenderDrawColor(_renderer, previousR, previousG, previousB, previousA); + SDL_SetRenderDrawBlendMode(_renderer, previousBlendMode); } diff --git a/src/protocol/connection_reader.cpp b/src/protocol/connection_reader.cpp index b6ce80b..19d84a6 100644 --- a/src/protocol/connection_reader.cpp +++ b/src/protocol/connection_reader.cpp @@ -170,6 +170,7 @@ void ConnectionReader::onUsbRead(libusb_transfer *transfer) void ConnectionReader::readLoop() { setThreadName("usb-read"); + setThreadPriority(ThreadPriority::Realtime); timeval timeout{0, 100000}; log_d("USB reading thread started");