From e6dfd73e7a8255bb798cd3c13e5fdd46a10045b1 Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Mon, 15 Mar 2021 01:37:25 +0100 Subject: [PATCH] Dynamic adjustment of the terminal refresh rate between 5 and 60 Hz --- ChangeLog | 6 ++++- src/fkeyboard.cpp | 10 +++----- src/ftermcap.cpp | 1 - src/fvterm.cpp | 52 +++++++++++++++++++++++++++++++++++++- src/include/final/fvterm.h | 6 +++++ test/ftermcap-test.cpp | 7 +++++ 6 files changed, 73 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index c8ca9cc2..8434512c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ -2021-02-09 Markus Gans +2021-03-15 Markus Gans + * Dynamic adjustment of the terminal refresh rate between + 5 and 60 Hz + +2021-03-09 Markus Gans * Implementation of an own padding print method for sending control codes to the terminal diff --git a/src/fkeyboard.cpp b/src/fkeyboard.cpp index 33ecfdfe..ac8ab0af 100644 --- a/src/fkeyboard.cpp +++ b/src/fkeyboard.cpp @@ -149,13 +149,11 @@ bool FKeyboard::isKeyPressed (uInt64 blocking_time) tv.tv_sec = tv.tv_usec = 0; // Non-blocking input if ( blocking_time > 0 - && non_blocking_input_support - && select(stdin_no + 1, &ifds, nullptr, nullptr, &tv) > 0 - && FD_ISSET(stdin_no, &ifds) ) + && non_blocking_input_support + && select(stdin_no + 1, &ifds, nullptr, nullptr, &tv) > 0 + && FD_ISSET(stdin_no, &ifds) ) { - has_pending_input = true; - FD_CLR (stdin_no, &ifds); - tv.tv_sec = 0; + return (has_pending_input = true); } if ( isKeypressTimeout() || ! non_blocking_input_support ) diff --git a/src/ftermcap.cpp b/src/ftermcap.cpp index 5aed9aa1..9f5cf9e7 100644 --- a/src/ftermcap.cpp +++ b/src/ftermcap.cpp @@ -438,7 +438,6 @@ std::string FTermcap::encodeParams ( const std::string& cap //---------------------------------------------------------------------- void FTermcap::delay_output (int ms, const defaultPutChar& outc) { - if ( no_padding_char ) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 7f35e105..743472ee 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -60,7 +60,9 @@ bool FVTerm::combined_char_support{false}; bool FVTerm::no_terminal_updates{false}; bool FVTerm::cursor_hideable{false}; bool FVTerm::force_terminal_update{false}; -uInt64 FVTerm::flush_wait{16667}; // 16.6 ms (60 Hz) +uInt64 FVTerm::flush_wait{MIN_FLUSH_WAIT}; +uInt64 FVTerm::flush_average{MIN_FLUSH_WAIT}; +uInt64 FVTerm::flush_median{MIN_FLUSH_WAIT}; uInt64 FVTerm::term_size_check_timeout{500000}; // 500 ms uInt FVTerm::erase_char_length{}; uInt FVTerm::repeat_char_length{}; @@ -573,6 +575,8 @@ void FVTerm::flush() const { // Flush the output buffer + flushTimeAdjustment(); + if ( ! output_buffer || output_buffer->empty() || ! (isFlushTimeout() || force_terminal_update) ) return; @@ -2888,6 +2892,52 @@ inline bool FVTerm::isTermSizeChanged() const return false; } +//---------------------------------------------------------------------- +inline void FVTerm::flushTimeAdjustment() const +{ + timeval now; + FObject::getCurrentTime(&now); + timeval diff = now - time_last_flush; + + if ( diff.tv_sec > 0 || diff.tv_usec > 400000 ) + { + flush_wait = MIN_FLUSH_WAIT; // Reset to minimum values after 400 ms + flush_average = MIN_FLUSH_WAIT; + flush_median = MIN_FLUSH_WAIT; + } + else + { + uInt64 usec = diff.tv_usec; + + if ( usec < MIN_FLUSH_WAIT ) + usec = MIN_FLUSH_WAIT; + else if ( usec > MAX_FLUSH_WAIT ) + usec = MAX_FLUSH_WAIT; + + if ( usec >= flush_average ) + flush_average += (usec - flush_average) / 10; + else + { + uInt64 delta = (flush_average - usec) / 10; + + if ( flush_average >= delta ) // Avoid uInt64 underflow + flush_average -= delta; + } + + if ( usec >= flush_median ) + flush_median += flush_average / 5; + else + { + uInt64 delta = flush_average / 5; + + if ( flush_median >= delta ) // Avoid uInt64 underflow + flush_median -= delta; + } + + flush_wait = flush_median; + } +} + //---------------------------------------------------------------------- inline bool FVTerm::isFlushTimeout() { diff --git a/src/include/final/fvterm.h b/src/include/final/fvterm.h index 5a9a1dc0..1f8ac306 100644 --- a/src/include/final/fvterm.h +++ b/src/include/final/fvterm.h @@ -345,6 +345,9 @@ class FVTerm // Constants // Buffer limit for character output on the terminal static constexpr std::size_t TERMINAL_OUTPUT_BUFFER_LIMIT = 1024; + // Upper and lower flush limit + static constexpr uInt64 MIN_FLUSH_WAIT = 16667; // 16.6 ms = 60 Hz + static constexpr uInt64 MAX_FLUSH_WAIT = 200000; // 200.0 ms = 5 Hz // Methods void resetTextAreaToDefault ( const FTermArea* @@ -412,6 +415,7 @@ class FVTerm bool updateTerminalCursor() const; bool isInsideTerminal (const FPoint&) const; bool isTermSizeChanged() const; + void flushTimeAdjustment() const; static bool isFlushTimeout(); static bool isTermSizeCheckTimeout(); static bool hasPendingUpdates (const FTermArea*); @@ -451,6 +455,8 @@ class FVTerm static bool no_terminal_updates; static bool force_terminal_update; static uInt64 flush_wait; + static uInt64 flush_average; + static uInt64 flush_median; static uInt64 term_size_check_timeout; static uInt erase_char_length; static uInt repeat_char_length; diff --git a/test/ftermcap-test.cpp b/test/ftermcap-test.cpp index 2e0c0c65..856d6cec 100644 --- a/test/ftermcap-test.cpp +++ b/test/ftermcap-test.cpp @@ -276,6 +276,13 @@ void FTermcapTest::paddingPrintTest() CPPUNIT_ASSERT ( ! output.empty() ); CPPUNIT_ASSERT ( output == "12$3$<4567" ); + // Without a digit + output.clear(); + status = tcap.paddingPrint ("12$3$4567", 1, FTermcapTest::putchar_test); + CPPUNIT_ASSERT ( status == finalcut::FTermcap::Status::OK ); + CPPUNIT_ASSERT ( ! output.empty() ); + CPPUNIT_ASSERT ( output == "12$3$4567" ); + // With 2 ms print delay output.clear(); auto start = high_resolution_clock::now();