From 6ece8054ac5691bf5bae9e979f3ddf05d74ec7a9 Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Thu, 23 Jul 2026 13:41:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DemoGallery/main.cpp | 40 +--- YSGraphic_Core/Axis/TimeAxis.cpp | 2 +- YSGraphic_Core/Axis/TimeAxis_p.h | 40 +++- YSGraphic_Core/DemoGallery/AfterglowPlot.h | 1 - YSGraphic_Core/DemoGallery/AudioPlot.h | 1 - YSGraphic_Core/DemoGallery/PlanispherePlot.h | 1 - YSGraphic_Core/DemoGallery/SpectrumPlot.h | 1 - .../DemoGallery/SweepFrequentPlot.h | 1 - YSGraphic_Core/DemoGallery/WaterFallPlot.h | 1 - YSGraphic_Core/DemoGallery/base/AxisTest.h | 1 - .../DemoGallery/base/FrequentAxis.h | 1 - .../DemoGallery/base/FrequentAxisTest.h | 1 - .../DemoGallery/base/MutiSelectTest.h | 1 - .../DemoGallery/base/TimeAxisTest.h | 1 - YSGraphic_Core/base/Global.cpp | 181 +++++++++--------- YSGraphic_Core/base/Global.h | 37 ++-- YSGraphic_Core/base/Plot.cpp | 90 ++++----- YSGraphic_Core/base/Plot.h | 7 +- YSGraphic_Core/base/Plot_p.h | 2 - YSGraphic_Core/base/RingBuffer.hpp | 112 ----------- YSGraphic_Core/base/export.h | 1 - YSGraphic_Core/plottable/AudioFrequent_p.h | 38 +++- 22 files changed, 211 insertions(+), 350 deletions(-) delete mode 100644 YSGraphic_Core/base/RingBuffer.hpp diff --git a/DemoGallery/main.cpp b/DemoGallery/main.cpp index 72b70ac..df5509c 100644 --- a/DemoGallery/main.cpp +++ b/DemoGallery/main.cpp @@ -14,7 +14,6 @@ #include "YSGraphic_Core/DemoGallery/SpectrumPlot.h" #include "YSGraphic_Core/DemoGallery/WaterFallPlot.h" #include "YSGraphic_Core/GenerateMockData.h" -#include "YSGraphic_Core/base/RingBuffer.hpp" #include "YSGraphic_Core/base/Graphic.h" #include "YSGraphic_Core/base/Plot.h" #include "YSGraphic_Core/component/Table/Table_View.h" @@ -26,43 +25,6 @@ #include "YSGraphic_Core/plottable/Spectrum_p.h" #include "YSGraphic_Core/plottable/WaterFall.h" #include "YSGraphic_Core/plottable/WaterFall_p.h" -#include "YSGraphic_Core/base/RingBuffer.hpp" -YSG::RingBuffer mRingBuffer{}; -int mBufferSize = 9; - -void print(const QString& prefix = "") { - int* list = mRingBuffer.list(); - QVector listData; - for(int i = 0; i < mRingBuffer.n; ++i){ - listData.push_back(list[i]); - } - int* buffer = reinterpret_cast(mRingBuffer.mData); - QVector bufferData; - for(int i = 0; i < mRingBuffer.m; ++i){ - bufferData.push_back(buffer[i]); - } - qDebug() << prefix << listData << " " << bufferData; - //qDebug() << "dataArray:" << dataArray; -} - -void f() { - mRingBuffer.isLeft = true; - mBufferSize = 7; - mRingBuffer.resize(sizeof(int), 4, mBufferSize); - QVector data(mBufferSize); - for(int i = 0; i < mBufferSize; ++i) { - //data[i] = i; - data[i] = -1; - } - std::memcpy(mRingBuffer.mData, data.data(), sizeof(int) * data.size()); - - for(int i = 1; i < 20; ++i) { - int data = i * 10; - mRingBuffer.pushData(reinterpret_cast(&data)); - print(QString("%1:").arg(i)); - } -} - namespace Table_Space { struct Base_Table_Model { @@ -284,7 +246,7 @@ int main(int argc, char *argv[]) { - YSG::startAllRenderThread(); + YSG::startRenderScheduler(); qDebug() << "启动耗时 " << timer.elapsed(); diff --git a/YSGraphic_Core/Axis/TimeAxis.cpp b/YSGraphic_Core/Axis/TimeAxis.cpp index 1825930..d57d0dd 100644 --- a/YSGraphic_Core/Axis/TimeAxis.cpp +++ b/YSGraphic_Core/Axis/TimeAxis.cpp @@ -24,7 +24,7 @@ namespace YSG { QTime TimeAxis::tickToTime(int tick, SRC src) { INIT_GET(TimeAxis) int offset = tick - (int)renderState->coordStart; - return *(d()->mRingBuffer.list() + offset); + return d()->timeByOffset(offset); } TimeAxis::Builder::Builder(Plot* plot, Qt::Orientation orientation) { this->plot = plot; diff --git a/YSGraphic_Core/Axis/TimeAxis_p.h b/YSGraphic_Core/Axis/TimeAxis_p.h index 28aa9a3..d0733df 100644 --- a/YSGraphic_Core/Axis/TimeAxis_p.h +++ b/YSGraphic_Core/Axis/TimeAxis_p.h @@ -3,13 +3,9 @@ #include "AbsAxis_p.h" #include "Core/Base/RingBuffer.hpp" #include "TimeAxis.h" - - +#include +#include #include - -#include "YSGraphic_Core/base/RingBuffer.hpp" - - namespace YSG { struct TimeTicker { @@ -92,8 +88,33 @@ namespace YSG { int mTickPixelSpace; QFont mFont; QString mTimeFormat; - YSG::RingBuffer mRingBuffer; + Psc::StreamRingBuffer_ST buffer; + std::vector mTimeSnapshot; + int mTimeDataCount{}; std::list mData; + void resizeTimeBuffer(int count) { + buffer.init(sizeof(QTime) * count); + mTimeSnapshot.resize(count); + mTimeDataCount = 0; + } + void pushTime(const QTime& time) { + if(mTimeDataCount == mTimeTicker.mTimePointSize) { + QTime ignored; + std::size_t len = sizeof(QTime); + buffer.read(&ignored, len); + --mTimeDataCount; + } + buffer.write(&time, sizeof(QTime)); + ++mTimeDataCount; + } + void snapshotTimeBuffer() { + buffer.peek_best_effort(mTimeSnapshot.data(), sizeof(QTime) * mTimeDataCount); + } + QTime timeByOffset(int offset) const { + int index = mTimeTicker.mStartCoordToEndCoord ? mTimeDataCount - 1 - offset : offset - (mTimeTicker.mTimePointSize - mTimeDataCount); + if(index < 0 || index >= mTimeDataCount) return {}; + return mTimeSnapshot[index]; + } void prepareData() override { syncStatePipeline(); auto d = renderInputData(); @@ -104,7 +125,7 @@ namespace YSG { bool refreshSpace = false; if(mTimeTicker.mTimePointSize != s->timePointSize) { mTimeTicker.setTimePointSize(s->timePointSize); - mRingBuffer.resize(sizeof(QTime), s->timePointSize, 10 * s->timePointSize); + resizeTimeBuffer(s->timePointSize); mData.clear(); refreshSpace = true; } @@ -141,8 +162,9 @@ namespace YSG { for(QTime& time : d->mAllTime) { - mRingBuffer.pushData(&time); + pushTime(time); } + snapshotTimeBuffer(); d->mAllTime.clear(); mData.splice(mData.begin(), d->mData); diff --git a/YSGraphic_Core/DemoGallery/AfterglowPlot.h b/YSGraphic_Core/DemoGallery/AfterglowPlot.h index 9d7f9b8..08836eb 100644 --- a/YSGraphic_Core/DemoGallery/AfterglowPlot.h +++ b/YSGraphic_Core/DemoGallery/AfterglowPlot.h @@ -12,7 +12,6 @@ static QWidget* createAfterglow() { void init() override { Plot::init(); mObjectName = "AfterglowPlot"; - bindRenderThread(mObjectName + "Thread"); xAxis = YSG::FrequentAxis::Builder(this, Qt::Horizontal).build(); yAxis = YSG::Axis::Builder(this, Qt::Vertical).build(); ag = YSG::Afterglow::Builder(xAxis, yAxis) diff --git a/YSGraphic_Core/DemoGallery/AudioPlot.h b/YSGraphic_Core/DemoGallery/AudioPlot.h index d4945ae..ea77422 100644 --- a/YSGraphic_Core/DemoGallery/AudioPlot.h +++ b/YSGraphic_Core/DemoGallery/AudioPlot.h @@ -13,7 +13,6 @@ static QWidget* createAudioPlot() { void init() override { Plot::init(); mObjectName = "AudioPlot"; - bindRenderThread(mObjectName + "Thread"); xAxis = YSG::TimeAxis::Builder(this, Qt::Horizontal) .set_tickLength(-10) .set_subTickLength(-5).build(); diff --git a/YSGraphic_Core/DemoGallery/PlanispherePlot.h b/YSGraphic_Core/DemoGallery/PlanispherePlot.h index 0372883..ca554a6 100644 --- a/YSGraphic_Core/DemoGallery/PlanispherePlot.h +++ b/YSGraphic_Core/DemoGallery/PlanispherePlot.h @@ -13,7 +13,6 @@ static QWidget* createPlanispherePlot() { void init() override { Plot::init(); mObjectName = "PlanispherePlot"; - bindRenderThread(mObjectName + "Thread"); xAxis = YSG::Axis::Builder(this, Qt::Horizontal) diff --git a/YSGraphic_Core/DemoGallery/SpectrumPlot.h b/YSGraphic_Core/DemoGallery/SpectrumPlot.h index 5817572..4f2ebb8 100644 --- a/YSGraphic_Core/DemoGallery/SpectrumPlot.h +++ b/YSGraphic_Core/DemoGallery/SpectrumPlot.h @@ -12,7 +12,6 @@ static QWidget* createSpectrunPlot() { void init() override { Plot::init(); mObjectName = "SpectrumPlot"; - bindRenderThread(mObjectName + "Thread"); xAxis = YSG::FrequentAxis::Builder(this, Qt::Horizontal) .set_coordRange({0, 100}) .set_tickLength(-10) diff --git a/YSGraphic_Core/DemoGallery/SweepFrequentPlot.h b/YSGraphic_Core/DemoGallery/SweepFrequentPlot.h index 100e83c..d787142 100644 --- a/YSGraphic_Core/DemoGallery/SweepFrequentPlot.h +++ b/YSGraphic_Core/DemoGallery/SweepFrequentPlot.h @@ -12,7 +12,6 @@ static QWidget* createSweepFrequentPlot() { void init() override { Plot::init(); mObjectName = "AxisTestPlot"; - bindRenderThread(mObjectName + "Thread"); xAxis = YSG::Axis::Builder(this, Qt::Horizontal) .set_coordRange({0, 100}) diff --git a/YSGraphic_Core/DemoGallery/WaterFallPlot.h b/YSGraphic_Core/DemoGallery/WaterFallPlot.h index a070fc0..11bd8a2 100644 --- a/YSGraphic_Core/DemoGallery/WaterFallPlot.h +++ b/YSGraphic_Core/DemoGallery/WaterFallPlot.h @@ -12,7 +12,6 @@ static QWidget* createWaterFallPlot() { void init() override { Plot::init(); mObjectName = "WaterFallPlot"; - bindRenderThread(mObjectName + "Thread"); xAxis = YSG::FrequentAxis::Builder(this, Qt::Horizontal) .set_tickLength(-10) diff --git a/YSGraphic_Core/DemoGallery/base/AxisTest.h b/YSGraphic_Core/DemoGallery/base/AxisTest.h index 95a2658..476b35e 100644 --- a/YSGraphic_Core/DemoGallery/base/AxisTest.h +++ b/YSGraphic_Core/DemoGallery/base/AxisTest.h @@ -9,7 +9,6 @@ static QWidget* createAxisTestPlot() { void init() override { Plot::init(); mObjectName = "AxisTestPlot"; - bindRenderThread("AxisTestPlotThread"); axis = YSG::Axis::Builder(this, Qt::Horizontal) .set_tickLength(-10) .set_subTickLength(-5) diff --git a/YSGraphic_Core/DemoGallery/base/FrequentAxis.h b/YSGraphic_Core/DemoGallery/base/FrequentAxis.h index d275438..78ce53c 100644 --- a/YSGraphic_Core/DemoGallery/base/FrequentAxis.h +++ b/YSGraphic_Core/DemoGallery/base/FrequentAxis.h @@ -10,7 +10,6 @@ static QWidget* createFrequentAxisTestPlot() { void init() override { Plot::init(); mObjectName = "AxisTestPlot"; - bindRenderThread("AxisTestPlotThread"); axis = new YSG::FrequentAxis; axis->init(this, "axis"); axis->setOrientation(Qt::Horizontal); diff --git a/YSGraphic_Core/DemoGallery/base/FrequentAxisTest.h b/YSGraphic_Core/DemoGallery/base/FrequentAxisTest.h index 99a095e..2def7e3 100644 --- a/YSGraphic_Core/DemoGallery/base/FrequentAxisTest.h +++ b/YSGraphic_Core/DemoGallery/base/FrequentAxisTest.h @@ -10,7 +10,6 @@ static QWidget* createFrequentAxisTestPlot() { void init() override { Plot::init(); mObjectName = "AxisTestPlot"; - bindRenderThread("AxisTestPlotThread"); axis = YSG::FrequentAxis::Builder(this, Qt::Horizontal) .set_tickLength(-10) .set_subTickLength(-5) diff --git a/YSGraphic_Core/DemoGallery/base/MutiSelectTest.h b/YSGraphic_Core/DemoGallery/base/MutiSelectTest.h index 0ec086b..f7025f5 100644 --- a/YSGraphic_Core/DemoGallery/base/MutiSelectTest.h +++ b/YSGraphic_Core/DemoGallery/base/MutiSelectTest.h @@ -13,7 +13,6 @@ static QWidget* createMutiSelectPlot() { void init() override { Plot::init(); mObjectName = "PlanispherePlot"; - bindRenderThread("PlanispherePlotThread"); xAxis = YSG::Axis::Builder(this, Qt::Horizontal) .set_tickLength(-10) diff --git a/YSGraphic_Core/DemoGallery/base/TimeAxisTest.h b/YSGraphic_Core/DemoGallery/base/TimeAxisTest.h index 54159c0..1f00693 100644 --- a/YSGraphic_Core/DemoGallery/base/TimeAxisTest.h +++ b/YSGraphic_Core/DemoGallery/base/TimeAxisTest.h @@ -10,7 +10,6 @@ static QWidget* createTimeAxisTestPlot() { void init() override { Plot::init(); mObjectName = "TimeAxisTestPlot"; - bindRenderThread(mObjectName + "Thread"); axis = YSG::TimeAxis::Builder(this, Qt::Horizontal) .set_tickLength(-10) .set_subTickLength(-5).build(); diff --git a/YSGraphic_Core/base/Global.cpp b/YSGraphic_Core/base/Global.cpp index 112ea37..811ae99 100644 --- a/YSGraphic_Core/base/Global.cpp +++ b/YSGraphic_Core/base/Global.cpp @@ -1,107 +1,109 @@ #include "asio.hpp" #include "Global.h" -#include -#include -#include -#include -#include -#include #include "Plot_p.h" - +#include +#include namespace YSG { - struct TimerThreadPrivate { + struct RenderSchedulerPrivate { asio::io_context mIoContext; std::unique_ptr> mWorkGuard; std::unique_ptr mCpuPool; + std::thread mSchedulerThread; std::thread::id mSchedulerThreadId; - std::atomic_bool mIoActive{false}; - std::atomic_bool mCpuJoined{false}; + QList mPlots; + std::atomic_bool mRunning{false}; + std::atomic_bool mCpuJoined{true}; }; - - TimerThread::TimerThread() : d(std::make_unique()) { - connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() { + RenderScheduler::RenderScheduler() : d(std::make_unique()) { + QObject::connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() { shutdown(); - delete this; }); } - TimerThread::~TimerThread() = default; - - void TimerThread::run() { - d->mSchedulerThreadId = std::this_thread::get_id(); + RenderScheduler::~RenderScheduler() { + shutdown(); + } + void RenderScheduler::start() { + if(d->mRunning.exchange(true, std::memory_order_acq_rel)) return; d->mIoContext.restart(); d->mWorkGuard = std::make_unique>(d->mIoContext.get_executor()); unsigned cpuCount = std::max(1u, std::thread::hardware_concurrency() > 1 ? std::thread::hardware_concurrency() - 1 : 1u); d->mCpuPool = std::make_unique(cpuCount); d->mCpuJoined.store(false, std::memory_order_release); - d->mIoActive.store(true, std::memory_order_release); - for (auto &plot: mPlots) { - plot->d->mTimerThread = this; - plot->d->mRenderTimer = std::make_unique(d->mIoContext); - plot->d->mRenderSize = QSize(plot->d->mPendingRenderWidth.load(std::memory_order_acquire), plot->d->mPendingRenderHeight.load(std::memory_order_acquire)); - if(plot->isVisible()) plot->d->mRenderEnabled.store(true, std::memory_order_release); - if(plot->d->mRenderEnabled.load(std::memory_order_acquire)) plot->scheduleRenderTimer(); - plot->requestRender(); - } - d->mIoContext.run(); - d->mIoActive.store(false, std::memory_order_release); - for (auto &plot: mPlots) { - if(plot->d->mRenderTimer) { - plot->d->mRenderTimer->cancel(); - plot->d->mRenderTimer.reset(); + d->mSchedulerThread = std::thread([this]() { + d->mSchedulerThreadId = std::this_thread::get_id(); + for(Plot* plot : d->mPlots) { + initializePlotOnScheduler(plot); } - } - joinCpuPool(); - d->mCpuPool.reset(); - d->mWorkGuard.reset(); + d->mIoContext.run(); + d->mRunning.store(false, std::memory_order_release); + }); } - void TimerThread::post(std::function task) { + void RenderScheduler::shutdown() { + if(!d->mRunning.load(std::memory_order_acquire)) { + joinCpuPool(); + if(d->mSchedulerThread.joinable() && d->mSchedulerThread.get_id() != std::this_thread::get_id()) d->mSchedulerThread.join(); + d->mCpuPool.reset(); + d->mWorkGuard.reset(); + return; + } + if(isSchedulerThread()) { + shutdownOnScheduler(); + d->mWorkGuard.reset(); + joinCpuPool(); + return; + } + postAndWait([this]() { + shutdownOnScheduler(); + }); + joinCpuPool(); + post([this]() { + d->mWorkGuard.reset(); + }); + if(d->mSchedulerThread.joinable()) d->mSchedulerThread.join(); + d->mCpuPool.reset(); + } + void RenderScheduler::post(std::function task) { asio::post(d->mIoContext, std::move(task)); } - void TimerThread::postCpu(std::function task) { + void RenderScheduler::postCpu(std::function task) { if(d->mCpuPool) { asio::post(*d->mCpuPool, std::move(task)); } else { post(std::move(task)); } } - bool TimerThread::isSchedulerThread() const { + void RenderScheduler::registerPlot(Plot* plot) { + if(d->mRunning.load(std::memory_order_acquire) && !isSchedulerThread()) { + postAndWait([this, plot]() { + registerPlotOnScheduler(plot); + }); + return; + } + registerPlotOnScheduler(plot); + } + void RenderScheduler::removePlot(Plot* plot) { + if(d->mRunning.load(std::memory_order_acquire) && !isSchedulerThread()) { + postAndWait([this, plot]() { + removePlotOnScheduler(plot); + }); + return; + } + removePlotOnScheduler(plot); + } + bool RenderScheduler::isSchedulerThread() const { return std::this_thread::get_id() == d->mSchedulerThreadId; } - asio::io_context& TimerThread::ioContext() { + bool RenderScheduler::isRunning() const { + return d->mRunning.load(std::memory_order_acquire); + } + asio::io_context& RenderScheduler::ioContext() { return d->mIoContext; } - void TimerThread::removePlot(Plot* plot) { - postAndWait([this, plot]() { - removePlotOnScheduler(plot); - }); - } - void TimerThread::shutdown() { - if(!isRunning()) { - shutdownOnScheduler(); - stopSchedulerOnScheduler(); - joinCpuPool(); - d->mCpuPool.reset(); - return; - } - if(isSchedulerThread()) { - shutdownOnScheduler(); - stopSchedulerOnScheduler(); - return; - } - postAndWait([this]() { - shutdownOnScheduler(); - }); - joinCpuPool(); - postAndWait([this]() { - stopSchedulerOnScheduler(); - }); - wait(); - } - void TimerThread::joinCpuPool() { + void RenderScheduler::joinCpuPool() { if(d->mCpuPool && !d->mCpuJoined.exchange(true, std::memory_order_acq_rel)) d->mCpuPool->join(); } - void TimerThread::postAndWait(std::function task) { - if(isSchedulerThread() || !isRunning() || !d->mIoActive.load(std::memory_order_acquire)) { + void RenderScheduler::postAndWait(std::function task) { + if(isSchedulerThread() || !d->mRunning.load(std::memory_order_acquire)) { task(); return; } @@ -121,18 +123,21 @@ namespace YSG { return done; }); } - void TimerThread::removePlotOnScheduler(Plot* plot) { - mPlots.removeAll(plot); + void RenderScheduler::registerPlotOnScheduler(Plot* plot) { + if(!d->mPlots.contains(plot)) d->mPlots.append(plot); + if(d->mRunning.load(std::memory_order_acquire)) initializePlotOnScheduler(plot); + } + void RenderScheduler::removePlotOnScheduler(Plot* plot) { + d->mPlots.removeAll(plot); PlotPrivate* data = plot->d; data->mRenderEnabled.store(false, std::memory_order_release); if(data->mRenderTimer) { data->mRenderTimer->cancel(); data->mRenderTimer.reset(); } - data->mTimerThread = nullptr; } - void TimerThread::shutdownOnScheduler() { - for(Plot* plot : mPlots) { + void RenderScheduler::shutdownOnScheduler() { + for(Plot* plot : d->mPlots) { PlotPrivate* data = plot->d; data->mDestroying.store(true, std::memory_order_release); data->mRenderEnabled.store(false, std::memory_order_release); @@ -140,21 +145,21 @@ namespace YSG { data->mRenderTimer->cancel(); data->mRenderTimer.reset(); } - data->mTimerThread = nullptr; } - mPlots.clear(); + d->mPlots.clear(); } - void TimerThread::stopSchedulerOnScheduler() { - d->mWorkGuard.reset(); + void RenderScheduler::initializePlotOnScheduler(Plot* plot) { + PlotPrivate* data = plot->d; + if(!data->mRenderTimer) data->mRenderTimer = std::make_unique(d->mIoContext); + data->mRenderSize = QSize(data->mPendingRenderWidth.load(std::memory_order_acquire), data->mPendingRenderHeight.load(std::memory_order_acquire)); + if(plot->isVisible()) data->mRenderEnabled.store(true, std::memory_order_release); + if(data->mRenderEnabled.load(std::memory_order_acquire)) plot->scheduleRenderTimer(); + plot->submitRender(); } - - void Global::startAllTimeThread() { - for (auto &thread: mTimerThreadMap) { - if(!thread->isRunning()) thread->start(); - } + RenderScheduler& Global::renderScheduler() { + return mRenderScheduler; } - - void Global::timerEvent(QTimerEvent* event) { - Q_UNUSED(event) + void Global::startRenderScheduler() { + mRenderScheduler.start(); } } diff --git a/YSGraphic_Core/base/Global.h b/YSGraphic_Core/base/Global.h index 9cc3af9..95e8f60 100644 --- a/YSGraphic_Core/base/Global.h +++ b/YSGraphic_Core/base/Global.h @@ -1,48 +1,51 @@ #pragma once #include "../GlobalTypes.h" #include "Core/Base/global_include.h" - +#include +#include #include #include -#include +#include +#include #include - extern int qInitResources_resource(); namespace asio { class io_context; } namespace YSG { - struct TimerThreadPrivate; - class LIB_DECL TimerThread : public QThread { - Q_OBJECT + class Plot; + struct RenderSchedulerPrivate; + class LIB_DECL RenderScheduler { public: - QList mPlots; - TimerThread(); - ~TimerThread() override; - void run() override; + RenderScheduler(); + ~RenderScheduler(); + void start(); + void shutdown(); void post(std::function task); void postCpu(std::function task); + void registerPlot(Plot* plot); void removePlot(Plot* plot); - void shutdown(); bool isSchedulerThread() const; + bool isRunning() const; asio::io_context& ioContext(); private: void joinCpuPool(); void postAndWait(std::function task); + void registerPlotOnScheduler(Plot* plot); void removePlotOnScheduler(Plot* plot); void shutdownOnScheduler(); - void stopSchedulerOnScheduler(); - std::unique_ptr d; + void initializePlotOnScheduler(Plot* plot); + std::unique_ptr d; }; class LIB_DECL Global : public QObject, public Psc::Singleton { public: int r = qInitResources_resource(); - int mTimerId{}; - QMap mTimerThreadMap; int mInterval = 10; - void startAllTimeThread(); - void timerEvent(QTimerEvent *event) override; + RenderScheduler& renderScheduler(); + void startRenderScheduler(); QVector mColorMap = getTurboColorGradient(); + private: + RenderScheduler mRenderScheduler; }; } diff --git a/YSGraphic_Core/base/Plot.cpp b/YSGraphic_Core/base/Plot.cpp index 2aac1d7..969dd9c 100644 --- a/YSGraphic_Core/base/Plot.cpp +++ b/YSGraphic_Core/base/Plot.cpp @@ -8,20 +8,8 @@ namespace YSG { static void notifyRenderTaskDone(PlotPrivate* data) { if(data->mActiveRenderTasks.fetch_sub(1, std::memory_order_acq_rel) == 1) data->mRenderTaskDone.notify_all(); } - void startAllRenderThread() { - Global::instance()->startAllTimeThread(); - } - - void Plot::bindRenderThread(const QString& threadName) { - auto g = Global::instance(); - if (!g->mTimerThreadMap.contains(threadName)) { - auto newThread = new TimerThread; - g->mTimerThreadMap[threadName] = newThread; - newThread->setObjectName(threadName); - } - TimerThread* thread = g->mTimerThreadMap[threadName]; - thread->mPlots.append(this); - d->mTimerThread = thread; + void startRenderScheduler() { + Global::instance()->startRenderScheduler(); } Plot::Plot() { @@ -29,6 +17,7 @@ namespace YSG { setAttribute(Qt::WA_OpaquePaintEvent, true); setMouseTracking(true); setFocusPolicy(Qt::NoFocus); + Global::instance()->renderScheduler().registerPlot(this); } bool Plot::usePerformanceShower() { return d->mShower; @@ -48,7 +37,7 @@ namespace YSG { Plot::~Plot() { d->mDestroying.store(true, std::memory_order_release); d->mRenderEnabled.store(false, std::memory_order_release); - if(d->mTimerThread) d->mTimerThread->removePlot(this); + Global::instance()->renderScheduler().removePlot(this); { std::unique_lock lock(d->mRenderTaskMutex); d->mRenderTaskDone.wait(lock, [this]() { @@ -70,11 +59,10 @@ namespace YSG { void Plot::startRender() const { if(d->mDestroying.load(std::memory_order_acquire)) return; d->mRenderEnabled.store(true, std::memory_order_release); - if(!d->mTimerThread) return; Plot* self = const_cast(this); PlotPrivate* privateData = d; privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); - d->mTimerThread->post([self, privateData]() { + Global::instance()->renderScheduler().post([self, privateData]() { PlotPrivate* d = self->d; if(!d->mDestroying.load(std::memory_order_acquire)) { if(d->mRenderTimer) { @@ -90,11 +78,10 @@ namespace YSG { void Plot::pauseRender() const { d->mRenderEnabled.store(false, std::memory_order_release); if(d->mDestroying.load(std::memory_order_acquire)) return; - if(!d->mTimerThread) return; Plot* self = const_cast(this); PlotPrivate* privateData = d; privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); - d->mTimerThread->post([self, privateData]() { + Global::instance()->renderScheduler().post([self, privateData]() { PlotPrivate* d = self->d; if(!d->mDestroying.load(std::memory_order_acquire)) { if(d->mRenderTimer) { @@ -127,10 +114,11 @@ namespace YSG { d->mPaintBufferAcquireMode.store(mode, std::memory_order_release); } void Plot::submitRender() { - if(d->mTimerThread && d->mTimerThread->isRunning() && !d->mTimerThread->isSchedulerThread()) { + RenderScheduler& scheduler = Global::instance()->renderScheduler(); + if(!scheduler.isSchedulerThread()) { PlotPrivate* privateData = d; privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); - d->mTimerThread->post([this, privateData]() { + scheduler.post([this, privateData]() { if(!privateData->mDestroying.load(std::memory_order_acquire)) submitRender(); notifyRenderTaskDone(privateData); }); @@ -180,33 +168,26 @@ namespace YSG { RenderAble::ColorBuffer* color = colorLease.buffer; QColor background = d->mBackground; std::uint64_t version = pipeline.renderStateVersion; - TimerThread* thread = d->mTimerThread; pipeline.jobState = RenderAble::JobState::Running; - if(thread) { - PlotPrivate* privateData = d; - privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); - thread->postCpu([this, privateData, colorLease, color, renderSize, background, version, thread]() { - if(privateData->mDestroying.load(std::memory_order_acquire)) { - privateData->mPipeline.unmarkColor(colorLease); - notifyRenderTaskDone(privateData); - return; - } - renderColor(color, renderSize, background, version); + PlotPrivate* privateData = d; + privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); + scheduler.postCpu([this, privateData, colorLease, color, renderSize, background, version]() { + if(privateData->mDestroying.load(std::memory_order_acquire)) { privateData->mPipeline.unmarkColor(colorLease); - if(privateData->mDestroying.load(std::memory_order_acquire)) { - notifyRenderTaskDone(privateData); - return; - } - thread->post([this, privateData]() { - if(!privateData->mDestroying.load(std::memory_order_acquire)) finishRender(); - notifyRenderTaskDone(privateData); - }); - }); - } else { + notifyRenderTaskDone(privateData); + return; + } renderColor(color, renderSize, background, version); - pipeline.unmarkColor(colorLease); - finishRender(); - } + privateData->mPipeline.unmarkColor(colorLease); + if(privateData->mDestroying.load(std::memory_order_acquire)) { + notifyRenderTaskDone(privateData); + return; + } + Global::instance()->renderScheduler().post([this, privateData]() { + if(!privateData->mDestroying.load(std::memory_order_acquire)) finishRender(); + notifyRenderTaskDone(privateData); + }); + }); } void Plot::finishRender() { if(d->mDestroying.load(std::memory_order_acquire)) return; @@ -270,10 +251,9 @@ namespace YSG { } void Plot::requestRender() { if(d->mDestroying.load(std::memory_order_acquire)) return; - if(!d->mTimerThread) return; PlotPrivate* privateData = d; privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); - d->mTimerThread->post([this, privateData]() { + Global::instance()->renderScheduler().post([this, privateData]() { if(!d->mDestroying.load(std::memory_order_acquire)) submitRender(); notifyRenderTaskDone(privateData); }); @@ -302,16 +282,12 @@ namespace YSG { QSize renderSize = e->size(); d->mPendingRenderWidth.store(renderSize.width(), std::memory_order_release); d->mPendingRenderHeight.store(renderSize.height(), std::memory_order_release); - if(d->mTimerThread && d->mTimerThread->isRunning()) { - PlotPrivate* privateData = d; - privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); - d->mTimerThread->post([privateData, renderSize]() { - if(!privateData->mDestroying.load(std::memory_order_acquire)) privateData->mRenderSize = renderSize; - notifyRenderTaskDone(privateData); - }); - } else { - d->mRenderSize = renderSize; - } + PlotPrivate* privateData = d; + privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel); + Global::instance()->renderScheduler().post([privateData, renderSize]() { + if(!privateData->mDestroying.load(std::memory_order_acquire)) privateData->mRenderSize = renderSize; + notifyRenderTaskDone(privateData); + }); if(mFirstResize) { for(Layer* layer : mLayerList) { for(RenderAble* able : layer->mRenderAbles) { diff --git a/YSGraphic_Core/base/Plot.h b/YSGraphic_Core/base/Plot.h index 02e2bc7..972284e 100644 --- a/YSGraphic_Core/base/Plot.h +++ b/YSGraphic_Core/base/Plot.h @@ -3,8 +3,8 @@ #include #include "../RenderAble.h" namespace YSG { - void LIB_DECL startAllRenderThread(); - class TimerThread; + void LIB_DECL startRenderScheduler(); + class RenderScheduler; struct PlotPrivate; class PerformanceShower; enum class Plot_Buffer_Acquire_Mode : std::uint8_t { @@ -17,7 +17,6 @@ namespace YSG { bool usePerformanceShower(); void set_usePerformanceShower(bool use); - void bindRenderThread(const QString& threadName); virtual void init() { initLayer(); } @@ -65,7 +64,7 @@ namespace YSG { void finishRender(); void requestUpdate(const QRegion& region); void renderColor(RenderAble::ColorBuffer* color, QSize size, QColor background, std::uint64_t version); - friend class TimerThread; + friend class RenderScheduler; friend struct RenderAble; }; diff --git a/YSGraphic_Core/base/Plot_p.h b/YSGraphic_Core/base/Plot_p.h index 98e43c1..237a16c 100644 --- a/YSGraphic_Core/base/Plot_p.h +++ b/YSGraphic_Core/base/Plot_p.h @@ -5,7 +5,6 @@ #include #include #include -#include #include #include namespace YSG { @@ -13,7 +12,6 @@ namespace YSG { explicit PlotPrivate(Plot* plot) : q(plot) {}; Plot *q{}; int mRefreshTimesPreSecond = 30; - TimerThread* mTimerThread{}; std::unique_ptr mRenderTimer; std::atomic_bool mRenderEnabled{false}; std::atomic_bool mDestroying{false}; diff --git a/YSGraphic_Core/base/RingBuffer.hpp b/YSGraphic_Core/base/RingBuffer.hpp deleted file mode 100644 index 72bff36..0000000 --- a/YSGraphic_Core/base/RingBuffer.hpp +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace YSG { - class RingBuffer { - public: - // 用char*是因为我的内存 是紧密连接的 - // struct CustomType; CustomType* it; it[i] 这种形式是不行的 - template - [[nodiscard]] T* list() const { - return (T*)(mData+s*l); - } - int n{}, l{}, m{}; - // s,e 差值始终为 n-1 - int e{}, eMin{}, eMax{}; // [n-1, m-1] - int s{}, sMin{}, sMax{}; // [0, m-n] - int f = 0; - char* mData{}; - bool isLeft = true; - template - T* operator[](int offset) { - return reinterpret_cast(mData + offset * l); - } - void resize(int _l, int _n, int _m) { - n = _n; - l = _l; - m = _m; - eMin = n - 1; - eMax = m - 1; - sMin = 0; - sMax = m - n; - if(isLeft) { //向左移 初始在最右端 - s = sMax; e = eMax; - } else { - s = sMin; e = eMin; - } - f = 0; - delete []mData; - int size = m * l; - mData = new char[size]; - for(int i = 0; i < size; ++i) { - mData[i] = 0; - } - } - void pushData(void* data){ - if(f < n) { //共l次,前几次赋值逻辑和后面不一样 - - if(isLeft) { - // std::cout << "s == " << s << " sMin-1 " << (sMin-1) << std::endl; - //std::cout << "f == " << f << " dst " << l*(sMax+1) << " src " << l*sMax << " size=" << l*f << std::endl; - - - //std::cout << "f == " << f << " dst " << l* << " src " << l*sMax << " size=" << l*f << std::endl; - - //std::cout << "dst:" << (sMax+1) << " src" << sMax; - std::memmove(mData+l*(sMax+1), mData+l*sMax, l*f); - std::memmove(mData+l*sMax, data, l); - } else { - std::memmove(mData+l*(eMin-f), mData+l*(eMin-f+1), l*f); - std::memmove(mData+l*eMin, data, l); - } - f++; - return; - } - if(isLeft) { - s--; e--; - if(s == sMin-1) { - s = sMax; e = eMax; - std::memmove(mData+l*(sMax+1), mData, l*(n - 1)); - std::memmove(mData+l*sMax, data, l); - } else { - std::memmove(mData+l*s, data, l); - } - } else { - s++; e++; - if(e == eMax+1) { - s = sMin; e = eMin; - std::memmove(mData, mData+l*(eMin+1), l*(n - 1)); - std::memmove(mData+l*eMin, data, l); - } else { - std::memmove(mData+l*e, data, l); - } - } - } - }; - - class MutiRingBuffer { - public: - int bufferNum{}, n{}, m{}; - std::vector buffers; - void resize(std::vector _ls, int _n, int _m) { - n = _n; - m = _m; - bufferNum = (int)_ls.size(); - buffers.resize(bufferNum); - for(int i = 0; i < bufferNum; ++i) { - buffers[i].resize(_ls[i], _n, _m); - } - } - void pushData(const std::vector& datas) { - for(int i = 0; i < bufferNum; ++i) { - buffers[i].pushData(datas[i]); - } - } - }; -} - - - diff --git a/YSGraphic_Core/base/export.h b/YSGraphic_Core/base/export.h index 5f733fc..30c0f6a 100644 --- a/YSGraphic_Core/base/export.h +++ b/YSGraphic_Core/base/export.h @@ -1,7 +1,6 @@ #include "CircularLinkedList.hpp" #include "FileDialog/FileDialog.h" #include "Node.hpp" -#include "RingBuffer.hpp" #include "RollObject.h" #include "SingletonWidget.hpp" #include "VirtualKeyBoard/VirtualKeyBoard.h" diff --git a/YSGraphic_Core/plottable/AudioFrequent_p.h b/YSGraphic_Core/plottable/AudioFrequent_p.h index 64469aa..701afd1 100644 --- a/YSGraphic_Core/plottable/AudioFrequent_p.h +++ b/YSGraphic_Core/plottable/AudioFrequent_p.h @@ -7,8 +7,6 @@ #include "../Axis/TimeAxis_p.h" #include "../base/PerformanceShower_p.h" #include "../base/Plot_p.h" - - namespace YSG { struct AudioFrequentInputData : InputData { std::list mDataList; @@ -20,21 +18,44 @@ namespace YSG { struct AudioFrequentPrivate : RenderData { D_Ptr(AudioFrequent) - YSG::MutiRingBuffer mMutiBuffer; + Psc::StreamRingBuffer_ST buffer; + std::vector powerSnapshot; + int dataCount{}; + int pointCount{}; + void resizePowerBuffer(int count) { + pointCount = count; + dataCount = 0; + powerSnapshot.resize(count); + buffer.init(sizeof(double) * count); + } + void pushPower(double power) { + if(dataCount == pointCount) { + double ignored; + std::size_t len = sizeof(double); + buffer.read(&ignored, len); + --dataCount; + } + buffer.write(&power, sizeof(double)); + ++dataCount; + } + void snapshotPowerBuffer() { + buffer.peek_best_effort(powerSnapshot.data(), sizeof(double) * dataCount); + } void prepareData() override { syncStatePipeline(); AudioFrequentRenderState *s = renderState(); AudioFrequentInputData *d = renderInputData(); - if(mMutiBuffer.buffers.empty() || mMutiBuffer.n != s->timePointSize) { - mMutiBuffer.resize({sizeof(double)}, s->timePointSize, s->timePointSize * 10); + if(pointCount != s->timePointSize) { + resizePowerBuffer(s->timePointSize); PerformanceShower *shower = q()->mPlot->d->mShower; if(shower) { shower->setPerformanceLine("TimePointSize", PerformanceLine(QString("timePointSize:%1").arg(s->timePointSize))); } } for(double& power : d->mDataList) { - mMutiBuffer.pushData({&power}); + pushPower(power); } + snapshotPowerBuffer(); clearRenderInput(); } @@ -51,9 +72,8 @@ namespace YSG { QPen newPen = QPen(s->color); newPen.setWidth(0); painter->setPen(newPen); - auto l1 = mMutiBuffer.buffers[0].list(); - for(int i = 0; i < mMutiBuffer.buffers[0].f; ++i) { - double* power = l1 + i; + for(int i = 0; i < dataCount; ++i) { + double* power = powerSnapshot.data() + dataCount - 1 - i; int index = s->timeAxis->d()->mTimeTicker.mStartCoordToEndCoord ? start + i : start + s->timeAxis->d()->mTimeTicker.mTimePointSize - i; double x = s->timeAxis->coordToPixel(index, SRC::Render);