This commit is contained in:
2026-07-23 13:41:30 +08:00
parent 0545bb6872
commit 6ece8054ac
22 changed files with 211 additions and 350 deletions
+1 -1
View File
@@ -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;
+31 -9
View File
@@ -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)
-1
View File
@@ -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();
+93 -88
View File
@@ -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();
}
}
+20 -17
View File
@@ -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;
};
}
+33 -57
View File
@@ -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 -4
View File
@@ -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;
};
-2
View File
@@ -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};
-112
View File
@@ -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
View File
@@ -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"
+29 -9
View File
@@ -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);