From 8c252e47d4e046ffb39e8d0f76cbf13a68a5c175 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 7 Jan 2026 13:44:36 +0100 Subject: [PATCH 1/5] updated libzedmd --- platforms/config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/config.sh b/platforms/config.sh index f0035dd..ab34c7f 100755 --- a/platforms/config.sh +++ b/platforms/config.sh @@ -2,7 +2,7 @@ set -e -LIBZEDMD_SHA=4c8211ac91dfeae3665ebd2530b8d6b9ece8cbc1 +LIBZEDMD_SHA=5aa1ddaf630e76bf78beade55a61104d71f3e970 LIBSERUM_SHA=9beac4e47d83ea2384316150c5b131c467d1ef8d LIBPUPDMD_SHA=124f45e5ddd59ceb339591de88fcca72f8c54612 From 6edf5e46f6b9a08d99d5fad797ee5624da600da3 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 7 Jan 2026 14:29:25 +0100 Subject: [PATCH 2/5] removed frame ready flag and watch queue porsitions instead. That fixes the issue of postponing super fast frames --- include/DMDUtil/DMD.h | 1 - platforms/config.sh | 2 +- src/DMD.cpp | 111 ++++++++++++++++++++++++------------------ 3 files changed, 65 insertions(+), 49 deletions(-) diff --git a/include/DMDUtil/DMD.h b/include/DMDUtil/DMD.h index c000cf8..c954e33 100644 --- a/include/DMDUtil/DMD.h +++ b/include/DMDUtil/DMD.h @@ -230,7 +230,6 @@ class DMDUTILAPI DMD std::thread* m_pSerumThread; std::shared_mutex m_dmdSharedMutex; std::condition_variable_any m_dmdCV; - std::atomic m_dmdFrameReady; std::atomic m_stopFlag; std::atomic m_updateBufferQueuePosition; std::atomic m_pupSceneId; diff --git a/platforms/config.sh b/platforms/config.sh index ab34c7f..2f03da0 100755 --- a/platforms/config.sh +++ b/platforms/config.sh @@ -2,7 +2,7 @@ set -e -LIBZEDMD_SHA=5aa1ddaf630e76bf78beade55a61104d71f3e970 +LIBZEDMD_SHA=1d930c3ab3a17433861f9f97900062f1088d1e7b LIBSERUM_SHA=9beac4e47d83ea2384316150c5b131c467d1ef8d LIBPUPDMD_SHA=124f45e5ddd59ceb339591de88fcca72f8c54612 diff --git a/src/DMD.cpp b/src/DMD.cpp index ea56c51..84c0c58 100644 --- a/src/DMD.cpp +++ b/src/DMD.cpp @@ -25,12 +25,12 @@ #include "AlphaNumeric.h" #include "FrameUtil.h" #include "Logger.h" +#include "TimeUtils.h" #include "ZeDMD.h" #include "komihash/komihash.h" #include "pupdmd.h" #include "serum-decode.h" #include "serum.h" -#include "TimeUtils.h" #include "sockpp/tcp_connector.h" namespace DMDUtil @@ -150,7 +150,6 @@ DMD::DMD() } m_updateBufferQueuePosition.store(0, std::memory_order_release); m_stopFlag.store(false, std::memory_order_release); - m_dmdFrameReady.store(false, std::memory_order_release); m_updateBuffered = std::make_shared(); m_pAlphaNumeric = new AlphaNumeric(); @@ -477,7 +476,6 @@ void DMD::QueueUpdate(const std::shared_ptr dmdUpdate, bool buffered) memcpy(m_pUpdateBufferQueue[(++updateBufferQueuePosition) % DMDUTIL_FRAME_BUFFER_SIZE], dmdUpdate.get(), sizeof(Update)); m_updateBufferQueuePosition.store(updateBufferQueuePosition, std::memory_order_release); - m_dmdFrameReady.store(true, std::memory_order_release); Log(DMDUtil_LogLevel_DEBUG, "Queued Frame: position=%d, mode=%d, depth=%d", updateBufferQueuePosition, dmdUpdate->mode, dmdUpdate->depth); @@ -745,18 +743,23 @@ uint16_t DMD::GetNextBufferQueuePosition(uint16_t bufferPosition, const uint16_t void DMD::DmdFrameThread() { char name[DMDUTIL_MAX_NAME_SIZE] = {0}; + uint16_t bufferPosition = 0; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); + bufferPosition = m_updateBufferQueuePosition.load(std::memory_order_relaxed); + if (strcmp(m_romName, name) != 0) { strcpy(name, m_romName); @@ -767,10 +770,6 @@ void DMD::DmdFrameThread() std::this_thread::sleep_for(std::chrono::milliseconds(2)); - std::unique_lock ul(m_dmdSharedMutex); - m_dmdFrameReady.store(false, std::memory_order_release); - ul.unlock(); - if (m_stopFlag) { return; @@ -790,7 +789,6 @@ void DMD::ZeDMDThread() uint8_t indexBuffer[256 * 64] = {0}; uint8_t renderBuffer[256 * 64 * 3] = {0}; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); Config* const pConfig = Config::GetInstance(); @@ -799,9 +797,12 @@ void DMD::ZeDMDThread() while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) @@ -945,7 +946,6 @@ void DMD::SerumThread() Update* lastDmdUpdate = nullptr; uint8_t flags = 0; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); Config* const pConfig = Config::GetInstance(); @@ -979,9 +979,12 @@ void DMD::SerumThread() if (nextRotation == 0) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); } @@ -1227,7 +1230,6 @@ void DMD::PixelcadeDMDThread() uint16_t* rgb565Data = new uint16_t[targetLength]; memset(rgb565Data, 0, targetLength * sizeof(uint16_t)); - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); Config* const pConfig = Config::GetInstance(); @@ -1236,9 +1238,12 @@ void DMD::PixelcadeDMDThread() while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) { @@ -1411,15 +1416,17 @@ void DMD::LevelDMDThread() uint16_t bufferPosition = 0; uint8_t renderBuffer[256 * 64] = {0}; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) { @@ -1461,7 +1468,6 @@ void DMD::RGB24DMDThread() uint8_t rgb24Data[256 * 64 * 3] = {0}; uint8_t rgb24DataScaled[256 * 64 * 3] = {0}; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); Config* const pConfig = Config::GetInstance(); @@ -1470,9 +1476,12 @@ void DMD::RGB24DMDThread() while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) { @@ -1622,15 +1631,17 @@ void DMD::ConsoleDMDThread() uint16_t bufferPosition = 0; uint8_t renderBuffer[256 * 64] = {0}; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) { @@ -1744,7 +1755,6 @@ void DMD::DumpDMDTxtThread() FILE* f = nullptr; std::unordered_set seenHashes; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); Config* const pConfig = Config::GetInstance(); @@ -1754,9 +1764,12 @@ void DMD::DumpDMDTxtThread() while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) { @@ -1903,15 +1916,17 @@ void DMD::DumpDMDRawThread() std::chrono::steady_clock::time_point start; FILE* f = nullptr; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) { @@ -1978,15 +1993,17 @@ void DMD::PupDMDThread() uint8_t palette[192] = {0}; char name[DMDUTIL_MAX_NAME_SIZE] = {0}; - (void)m_dmdFrameReady.load(std::memory_order_acquire); (void)m_stopFlag.load(std::memory_order_acquire); while (true) { std::shared_lock sl(m_dmdSharedMutex); - m_dmdCV.wait( - sl, [&]() - { return m_dmdFrameReady.load(std::memory_order_relaxed) || m_stopFlag.load(std::memory_order_relaxed); }); + m_dmdCV.wait(sl, + [&]() + { + return m_stopFlag.load(std::memory_order_relaxed) || + (m_updateBufferQueuePosition.load(std::memory_order_relaxed) != bufferPosition); + }); sl.unlock(); if (m_stopFlag.load(std::memory_order_acquire)) { From 1360ab390283f656b7bb1fc205a59faf67e9400f Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Wed, 7 Jan 2026 18:45:53 +0100 Subject: [PATCH 3/5] updated libzedmd --- platforms/config.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/config.sh b/platforms/config.sh index 2f03da0..562bd2b 100755 --- a/platforms/config.sh +++ b/platforms/config.sh @@ -2,7 +2,7 @@ set -e -LIBZEDMD_SHA=1d930c3ab3a17433861f9f97900062f1088d1e7b +LIBZEDMD_SHA=22cdc59bdb110a13cf860766e39a50acc3a6fc1f LIBSERUM_SHA=9beac4e47d83ea2384316150c5b131c467d1ef8d LIBPUPDMD_SHA=124f45e5ddd59ceb339591de88fcca72f8c54612 From 4621c3b4184beaf8f4e9b6fc2007c94745d27682 Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 8 Jan 2026 12:54:23 +0100 Subject: [PATCH 4/5] libzedmd 0.10.1, libserum v2.4.1 --- README.md | 2 ++ dmdserver.ini | 2 ++ include/DMDUtil/Config.h | 3 +++ platforms/config.sh | 4 ++-- src/Config.cpp | 10 ++++++++++ src/DMD.cpp | 6 ++++-- 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 68af19d..2835631 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,8 @@ AltColor = 1 AltColorPath = # Set to 1 if PUP DMD frame matching should be used, 0 if not. PUPCapture = 1 +# Set to 1 if Serum PUP frame matching should be used, 0 if not. +SerumPUPTriggers = 0 # Overwrite the PUPVideosPath sent by the client and set it to a fixed value. PUPVideosPath = # Set to 1 if PUP DMD frame matching should respect the exact colors, 0 if not. diff --git a/dmdserver.ini b/dmdserver.ini index 6fe33d8..7c6f8af 100644 --- a/dmdserver.ini +++ b/dmdserver.ini @@ -11,6 +11,8 @@ AltColor = 1 AltColorPath = # Set to 1 if PUP DMD frame matching should be used, 0 if not. PUPCapture = 1 +# Set to 1 if Serum PUP frame matching should be used, 0 if not. +SerumPUPTriggers = 0 # Overwrite the PUPVideosPath sent by the client and set it to a fixed value. PUPVideosPath = # Set to 1 if PUP DMD frame matching should respect the exact colors, 0 if not. diff --git a/include/DMDUtil/Config.h b/include/DMDUtil/Config.h index 337a203..1cf196c 100644 --- a/include/DMDUtil/Config.h +++ b/include/DMDUtil/Config.h @@ -43,6 +43,8 @@ class DMDUTILAPI Config const char* GetAltColorPath() const { return m_altColorPath.c_str(); } bool IsPUPCapture() const { return m_pupCapture; } void SetPUPCapture(bool pupCapture) { m_pupCapture = pupCapture; } + bool IsSerumPUPTriggers() const { return m_serumPupTriggers; } + void SetSerumPUPTriggers(bool serumPupTriggers) { m_serumPupTriggers = serumPupTriggers; } void SetPUPVideosPath(const char* path) { m_pupVideosPath = path; } const char* GetPUPVideosPath() const { return m_pupVideosPath.c_str(); } bool IsPUPExactColorMatch() const { return m_pupExactColorMatch; } @@ -122,6 +124,7 @@ class DMDUTILAPI Config bool m_altColor; std::string m_altColorPath; bool m_pupCapture; + bool m_serumPupTriggers std::string m_pupVideosPath; bool m_pupExactColorMatch; int m_framesTimeout; diff --git a/platforms/config.sh b/platforms/config.sh index 562bd2b..e6d7aea 100755 --- a/platforms/config.sh +++ b/platforms/config.sh @@ -2,8 +2,8 @@ set -e -LIBZEDMD_SHA=22cdc59bdb110a13cf860766e39a50acc3a6fc1f -LIBSERUM_SHA=9beac4e47d83ea2384316150c5b131c467d1ef8d +LIBZEDMD_SHA=cb969273720234df2f11f2fd7c81fe375f83cfe2 +LIBSERUM_SHA=0c2e688dca271b2c3e1dc31fe71fc0276d33ffab LIBPUPDMD_SHA=124f45e5ddd59ceb339591de88fcca72f8c54612 if [ -z "${BUILD_TYPE}" ]; then diff --git a/src/Config.cpp b/src/Config.cpp index d116d5f..19c68b8 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -19,6 +19,7 @@ Config::Config() m_altColor = true; m_altColorPath.clear(); m_pupCapture = false; + m_serumPupTriggers = false; m_pupVideosPath.clear(); m_pupExactColorMatch = true; m_framesTimeout = 0; @@ -92,6 +93,15 @@ void Config::parseConfigFile(const char* path) SetPUPCapture(false); } + try + { + SetSerumPUPTriggers(r.Get("DMDServer", "SerumPUPTriggers", false)); + } + catch (const std::exception&) + { + SetSerumPUPTriggers(false); + } + try { SetPUPVideosPath(r.Get("DMDServer", "PUPVideosPath", "").c_str()); diff --git a/src/DMD.cpp b/src/DMD.cpp index 84c0c58..ce5358d 100644 --- a/src/DMD.cpp +++ b/src/DMD.cpp @@ -934,7 +934,9 @@ void DMD::ZeDMDThread() void DMD::SerumThread() { - if (Config::GetInstance()->IsAltColor()) + Config* const pConfig = Config::GetInstance(); + + if (pConfig->IsAltColor()) { Serum_SetLogCallback(Serum_LogCallback, nullptr); @@ -948,9 +950,9 @@ void DMD::SerumThread() (void)m_stopFlag.load(std::memory_order_acquire); - Config* const pConfig = Config::GetInstance(); bool showNotColorizedFrames = pConfig->IsShowNotColorizedFrames(); bool dumpNotColorizedFrames = pConfig->IsDumpNotColorizedFrames(); + if (pConfig->IsSerumPUPTriggers()) Serum_EnablePupTrigers(); while (true) { From 0b296a99f50567561999f27fdad6454be63b064d Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Thu, 8 Jan 2026 13:02:04 +0100 Subject: [PATCH 5/5] fixed compile issue --- include/DMDUtil/Config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/DMDUtil/Config.h b/include/DMDUtil/Config.h index 1cf196c..39151d8 100644 --- a/include/DMDUtil/Config.h +++ b/include/DMDUtil/Config.h @@ -124,7 +124,7 @@ class DMDUTILAPI Config bool m_altColor; std::string m_altColorPath; bool m_pupCapture; - bool m_serumPupTriggers + bool m_serumPupTriggers; std::string m_pupVideosPath; bool m_pupExactColorMatch; int m_framesTimeout;