From 51ed3f2ed08016532e7ded7449235d89a1ba78fe Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 9 Jul 2022 13:03:45 -0400 Subject: [PATCH] Reduce modal-related thread hopping. --- .../Mac/Clock Signal/ScanTarget/CSScanTarget.mm | 14 ++++++++------ Outputs/ScanTargets/BufferingScanTarget.cpp | 12 +++++++++--- Outputs/ScanTargets/BufferingScanTarget.hpp | 7 ++++++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm index 42548e778..a58a499b8 100644 --- a/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm +++ b/OSBindings/Mac/Clock Signal/ScanTarget/CSScanTarget.mm @@ -939,12 +939,14 @@ using BufferingScanTarget = Outputs::Display::BufferingScanTarget; - (void)updateFrameBuffer { // TODO: rethink BufferingScanTarget::perform. Is it now really just for guarding the modals? - _scanTarget.perform([=] { - const Outputs::Display::ScanTarget::Modals *const newModals = _scanTarget.new_modals(); - if(newModals) { - [self setModals:*newModals]; - } - }); + if(_scanTarget.has_new_modals()) { + _scanTarget.perform([=] { + const Outputs::Display::ScanTarget::Modals *const newModals = _scanTarget.new_modals(); + if(newModals) { + [self setModals:*newModals]; + } + }); + } @synchronized(self) { if(!_frameBufferRenderPass) return; diff --git a/Outputs/ScanTargets/BufferingScanTarget.cpp b/Outputs/ScanTargets/BufferingScanTarget.cpp index c5bc95002..e65b9a136 100644 --- a/Outputs/ScanTargets/BufferingScanTarget.cpp +++ b/Outputs/ScanTargets/BufferingScanTarget.cpp @@ -302,7 +302,7 @@ size_t BufferingScanTarget::write_area_data_size() const { void BufferingScanTarget::set_modals(Modals modals) { perform([=] { modals_ = modals; - modals_are_dirty_ = true; + modals_are_dirty_.store(true, std::memory_order::memory_order_relaxed); }); } @@ -374,10 +374,12 @@ void BufferingScanTarget::set_line_buffer(Line *line_buffer, LineMetadata *metad } const Outputs::Display::ScanTarget::Modals *BufferingScanTarget::new_modals() { - if(!modals_are_dirty_) { + const auto modals_are_dirty = modals_are_dirty_.load(std::memory_order::memory_order_relaxed); + if(!modals_are_dirty) { return nullptr; } - modals_are_dirty_ = false; + + modals_are_dirty_.store(false, std::memory_order::memory_order_relaxed); // MAJOR SHARP EDGE HERE: assume that because the new_modals have been fetched then the caller will // now ensure their texture buffer is appropriate. They might provide a new pointer and might now. @@ -392,3 +394,7 @@ const Outputs::Display::ScanTarget::Modals *BufferingScanTarget::new_modals() { const Outputs::Display::ScanTarget::Modals &BufferingScanTarget::modals() const { return modals_; } + +bool BufferingScanTarget::has_new_modals() const { + return modals_are_dirty_.load(std::memory_order::memory_order_relaxed); +} diff --git a/Outputs/ScanTargets/BufferingScanTarget.hpp b/Outputs/ScanTargets/BufferingScanTarget.hpp index 4b41d0a8b..83d8a3013 100644 --- a/Outputs/ScanTargets/BufferingScanTarget.hpp +++ b/Outputs/ScanTargets/BufferingScanTarget.hpp @@ -161,6 +161,11 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget { /// @returns the current @c Modals. const Modals &modals() const; + /// @returns @c true if new modals are available; @c false otherwise. + /// + /// Safe to call from any thread. + bool has_new_modals() const; + private: // ScanTarget overrides. void set_modals(Modals) final; @@ -253,7 +258,7 @@ class BufferingScanTarget: public Outputs::Display::ScanTarget { // Current modals and whether they've yet been returned // from a call to @c get_new_modals. Modals modals_; - bool modals_are_dirty_ = false; + std::atomic modals_are_dirty_ = false; // Provides a per-data size implementation of end_data; a previous // implementation used blind memcpy and that turned into something