优化
This commit is contained in:
@@ -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<QTime>() + offset);
|
||||
return d()->timeByOffset(offset);
|
||||
}
|
||||
TimeAxis::Builder::Builder(Plot* plot, Qt::Orientation orientation) {
|
||||
this->plot = plot;
|
||||
|
||||
@@ -3,13 +3,9 @@
|
||||
#include "AbsAxis_p.h"
|
||||
#include "Core/Base/RingBuffer.hpp"
|
||||
#include "TimeAxis.h"
|
||||
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <QTime>
|
||||
|
||||
#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<QTime> mTimeSnapshot;
|
||||
int mTimeDataCount{};
|
||||
std::list<TimeTick> 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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -13,7 +13,6 @@ static QWidget* createPlanispherePlot() {
|
||||
void init() override {
|
||||
Plot::init();
|
||||
mObjectName = "PlanispherePlot";
|
||||
bindRenderThread(mObjectName + "Thread");
|
||||
|
||||
|
||||
xAxis = YSG::Axis::Builder(this, Qt::Horizontal)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,107 +1,109 @@
|
||||
#include "asio.hpp"
|
||||
#include "Global.h"
|
||||
#include <QApplication>
|
||||
#include <atomic>
|
||||
#include <algorithm>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include "Plot_p.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <algorithm>
|
||||
namespace YSG {
|
||||
struct TimerThreadPrivate {
|
||||
struct RenderSchedulerPrivate {
|
||||
asio::io_context mIoContext;
|
||||
std::unique_ptr<asio::executor_work_guard<asio::io_context::executor_type>> mWorkGuard;
|
||||
std::unique_ptr<asio::thread_pool> mCpuPool;
|
||||
std::thread mSchedulerThread;
|
||||
std::thread::id mSchedulerThreadId;
|
||||
std::atomic_bool mIoActive{false};
|
||||
std::atomic_bool mCpuJoined{false};
|
||||
QList<Plot*> mPlots;
|
||||
std::atomic_bool mRunning{false};
|
||||
std::atomic_bool mCpuJoined{true};
|
||||
};
|
||||
|
||||
TimerThread::TimerThread() : d(std::make_unique<TimerThreadPrivate>()) {
|
||||
connect(QApplication::instance(), &QApplication::aboutToQuit, [this]() {
|
||||
RenderScheduler::RenderScheduler() : d(std::make_unique<RenderSchedulerPrivate>()) {
|
||||
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<asio::executor_work_guard<asio::io_context::executor_type>>(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<asio::thread_pool>(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<asio::steady_timer>(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<void()> 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<void()> task) {
|
||||
asio::post(d->mIoContext, std::move(task));
|
||||
}
|
||||
void TimerThread::postCpu(std::function<void()> task) {
|
||||
void RenderScheduler::postCpu(std::function<void()> 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<void()> task) {
|
||||
if(isSchedulerThread() || !isRunning() || !d->mIoActive.load(std::memory_order_acquire)) {
|
||||
void RenderScheduler::postAndWait(std::function<void()> 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<asio::steady_timer>(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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,51 @@
|
||||
#pragma once
|
||||
#include "../GlobalTypes.h"
|
||||
#include "Core/Base/global_include.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <QThread>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <qrgb.h>
|
||||
|
||||
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<Plot*> mPlots;
|
||||
TimerThread();
|
||||
~TimerThread() override;
|
||||
void run() override;
|
||||
RenderScheduler();
|
||||
~RenderScheduler();
|
||||
void start();
|
||||
void shutdown();
|
||||
void post(std::function<void()> task);
|
||||
void postCpu(std::function<void()> 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<void()> task);
|
||||
void registerPlotOnScheduler(Plot* plot);
|
||||
void removePlotOnScheduler(Plot* plot);
|
||||
void shutdownOnScheduler();
|
||||
void stopSchedulerOnScheduler();
|
||||
std::unique_ptr<TimerThreadPrivate> d;
|
||||
void initializePlotOnScheduler(Plot* plot);
|
||||
std::unique_ptr<RenderSchedulerPrivate> d;
|
||||
};
|
||||
class LIB_DECL Global : public QObject, public Psc::Singleton<Global> {
|
||||
public:
|
||||
int r = qInitResources_resource();
|
||||
int mTimerId{};
|
||||
QMap<QString, TimerThread*> mTimerThreadMap;
|
||||
int mInterval = 10;
|
||||
void startAllTimeThread();
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
RenderScheduler& renderScheduler();
|
||||
void startRenderScheduler();
|
||||
QVector<QRgb> mColorMap = getTurboColorGradient();
|
||||
private:
|
||||
RenderScheduler mRenderScheduler;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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<std::mutex> 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<Plot*>(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<Plot*>(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) {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <QTime>
|
||||
#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;
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <QApplication>
|
||||
#include <QThread>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
namespace YSG {
|
||||
@@ -13,7 +12,6 @@ namespace YSG {
|
||||
explicit PlotPrivate(Plot* plot) : q(plot) {};
|
||||
Plot *q{};
|
||||
int mRefreshTimesPreSecond = 30;
|
||||
TimerThread* mTimerThread{};
|
||||
std::unique_ptr<asio::steady_timer> mRenderTimer;
|
||||
std::atomic_bool mRenderEnabled{false};
|
||||
std::atomic_bool mDestroying{false};
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <QDebug>
|
||||
|
||||
namespace YSG {
|
||||
class RingBuffer {
|
||||
public:
|
||||
// 用char*是因为我的内存 是紧密连接的
|
||||
// struct CustomType; CustomType* it; it[i] 这种形式是不行的
|
||||
template<typename T = char>
|
||||
[[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 <typename T = char>
|
||||
T* operator[](int offset) {
|
||||
return reinterpret_cast<T*>(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<RingBuffer> buffers;
|
||||
void resize(std::vector<int> _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<void*>& datas) {
|
||||
for(int i = 0; i < bufferNum; ++i) {
|
||||
buffers[i].pushData(datas[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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<double> mDataList;
|
||||
@@ -20,21 +18,44 @@ namespace YSG {
|
||||
|
||||
struct AudioFrequentPrivate : RenderData {
|
||||
D_Ptr(AudioFrequent)
|
||||
YSG::MutiRingBuffer mMutiBuffer;
|
||||
Psc::StreamRingBuffer_ST buffer;
|
||||
std::vector<double> 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<double>();
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user