Files
Renderive/YSGraphic_Core/base/Plot.cpp
T
2026-07-23 11:10:17 +08:00

420 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "Plot_p.h"
#include "PerformanceShower_p.h"
#include "Global.h"
#include <algorithm>
#include <chrono>
namespace YSG {
class PrePareMutiDataMutexGuard {
public:
QVector<PrePareMutiDataMutex*> mLockList;
PrePareMutiDataMutexGuard(RenderAble* renderAble, Plot* plot) {
for(PrePareMutiDataMutex* curLock : plot->mMutiSpinLock) {
if(curLock->mSet.contains(renderAble)) {
mLockList.append(curLock);
}
}
for(PrePareMutiDataMutex* curLock : mLockList) curLock->lock(renderAble);
}
~PrePareMutiDataMutexGuard() {
for(PrePareMutiDataMutex* curLock : mLockList) curLock->unlock();
}
};
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;
}
Plot::Plot() {
d = new PlotPrivate(this);
setAttribute(Qt::WA_OpaquePaintEvent, true);
setMouseTracking(true);
setFocusPolicy(Qt::NoFocus);
}
bool Plot::usePerformanceShower() {
return d->mShower;
}
void Plot::set_usePerformanceShower(bool use) {
SpinLockGuard g(&d->mRenderLock);
if(!use) {
PerformanceShower* t = d->mShower;
d->mShower = nullptr;
delete t;
} else {
if(d->mShower) return;
d->mShower = new PerformanceShower(this);
d->mShower->show();
}
}
Plot::~Plot() {
d->mDestroying.store(true, std::memory_order_release);
d->mRenderEnabled = false;
if(d->mTimerThread) d->mTimerThread->removePlot(this);
{
std::unique_lock<std::mutex> lock(d->mRenderTaskMutex);
d->mRenderTaskDone.wait(lock, [this]() {
return d->mActiveRenderTasks.load(std::memory_order_acquire) == 0;
});
}
delete d;
}
bool Plot::isRendering() {
return d->mRenderEnabled;
}
void Plot::startRender(int refreshTimesPreSecond) {
d->mRefreshTimesPreSecond = refreshTimesPreSecond;
startRender();
}
void Plot::startRender() const {
if(d->mDestroying.load(std::memory_order_acquire)) return;
d->mRenderEnabled = true;
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]() {
PlotPrivate* d = self->d;
if(!d->mDestroying.load(std::memory_order_acquire)) {
if(d->mRenderTimer) {
d->mRenderTimer->cancel();
self->scheduleRenderTimer();
}
self->submitRender();
}
notifyRenderTaskDone(privateData);
});
}
void Plot::pauseRender() const {
d->mRenderEnabled = false;
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]() {
PlotPrivate* d = self->d;
if(!d->mDestroying.load(std::memory_order_acquire)) {
if(d->mRenderTimer) {
d->mRenderTimer->cancel();
}
}
notifyRenderTaskDone(privateData);
});
}
void Plot::paintEvent(QPaintEvent* event) {
Q_UNUSED(event)
QPainter painter(this);
auto colorLease = d->mPipeline.consumeReadyColor();
RenderAble::ColorBuffer* color = colorLease.buffer;
if(color && !color->image.isNull()) painter.drawImage(QPoint(0, 0), color->image);
else painter.fillRect(rect(), d->mBackground);
if(colorLease) d->mPipeline.unmarkColor(colorLease);
painter.end();
if(d->mShower) d->mShower->counterIncrease("plot paint");
}
void Plot::render() {
submitRender();
}
void Plot::submitRender() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(mFirstResize) return;
if(!d->mRenderEnabled) return;
QSize renderSize = d->mRenderSize;
if(renderSize.width() <= 0 || renderSize.height() <= 0) return;
RenderAble::RenderPipeline& pipeline = d->mPipeline;
if(pipeline.jobState != RenderAble::JobState::Idle) return;
if(!pipeline.hasNewState()) return;
pipeline.jobState = RenderAble::JobState::Queued;
pipeline.renderStateVersion = pipeline.editStateVersion.load(std::memory_order_acquire);
if(d->mShower) {
d->mShower->counterIncrease("渲染帧率");
d->mShower->mInfos["interval"] = QString("渲染:%1, global%2").arg(qRound(1000.0 / (double)d->mRefreshTimesPreSecond)).arg(Global::instance()->mInterval);
}
{
Cacl prepareData("准备数据耗时: %1 avg: %2", d->mShower);
SpinLockGuard prepareDataLock(&d->mPrepareDataLock);
for(Layer* layer : mLayerList) {
for(RenderAble *cur : layer->mRenderAbles) {
//qDebug() << "info: "<< layer->mLayerName << " " << cur->mObjectName;
for(auto rely : cur->mBeRelyList) {
if(!rely->mPrepared){
PrePareMutiDataMutexGuard _guard(rely, this);
// qDebug() << cur->mObjectName << "rely: " << mObjectName;
rely->prepareData();
rely->mPrepared = true;
}
}
if(!cur->mPrepared){
PrePareMutiDataMutexGuard _guard(cur, this);
cur->prepareData();
//qDebug() << cur->mObjectName << " prepareData";
cur->mPrepared = true;
}
}
}
if(mFirstPrepareData) mFirstPrepareData = false;
}
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->mPrepared = false;
}
}
auto colorLease = pipeline.waitRenderColor();
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);
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 {
renderColor(color, renderSize, background, version);
pipeline.unmarkColor(colorLease);
finishRender();
}
}
void Plot::finishRender() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
RenderAble::RenderPipeline& pipeline = d->mPipeline;
QRegion updateRegion = pipeline.publishRenderColor();
pipeline.jobState = RenderAble::JobState::Idle;
if(!updateRegion.isEmpty()) requestUpdate(updateRegion);
if(d->mShower) d->mShower->refresh();
if(pipeline.hasNewState()) submitRender();
}
void Plot::renderColor(RenderAble::ColorBuffer* color, QSize size, QColor background, std::uint64_t version) {
Cacl renderData("整体渲染耗时: %1 avg: %2", d->mShower);
if(color->image.size() != size || color->image.format() != QImage::Format_ARGB32) {
color->image = QImage(size, QImage::Format_ARGB32);
}
color->image.detach();
color->image.fill(background);
QVector<RenderData*> leasedData;
QVector<Triple_Buffer_Lease> stateLeases;
QPainter painter(&color->image);
{
Cacl drawData("draw耗时: %1 avg: %2", d->mShower);
for(Layer* layer : mLayerList) {
for(RenderAble* cur : layer->mRenderAbles) {
if(!cur->mVisable) continue;
leasedData.append(cur->dPtr);
stateLeases.append(cur->dPtr->waitMarkStateRole(State_Render));
}
}
for(Layer* layer : mLayerList) {
for(RenderAble* cur : layer->mRenderAbles) {
if(!cur->mVisable) continue;
cur->draw(&painter);
}
}
}
for(int i = 0; i < leasedData.size(); ++i) {
leasedData[i]->unmarkState(stateLeases[i]);
}
painter.end();
color->version.store(version, std::memory_order_release);
color->dirtyRegion = QRegion(QRect(QPoint(0, 0), size));
}
void Plot::scheduleRenderTimer() {
if(d->mDestroying.load(std::memory_order_acquire) || !d->mRenderTimer || !d->mRenderEnabled) return;
int interval = std::max(1, qRound(1000.0 / (double)d->mRefreshTimesPreSecond));
d->mRenderTimer->expires_after(std::chrono::milliseconds(interval));
PlotPrivate* privateData = d;
privateData->mActiveRenderTasks.fetch_add(1, std::memory_order_acq_rel);
d->mRenderTimer->async_wait([this, privateData](const asio::error_code& error) {
if(!error && !d->mDestroying.load(std::memory_order_acquire)) {
submitRender();
scheduleRenderTimer();
}
notifyRenderTaskDone(privateData);
});
}
void Plot::markRenderStateDirty() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
d->mPipeline.markEditState();
requestRender();
}
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]() {
if(!d->mDestroying.load(std::memory_order_acquire)) submitRender();
notifyRenderTaskDone(privateData);
});
}
void Plot::requestUpdate(const QRegion& region) {
QTimer::singleShot(0, this, [this, region]() {
if(d->mDestroying.load(std::memory_order_acquire)) return;
if(region.isEmpty()) update();
else update(region);
});
}
QColor Plot::backgroundColor() {
return d->mBackground;
}
void Plot::setBackgroundColor(const QColor& color) const {
d->mBackground = color;
}
bool Plot::event(QEvent* event) {
bool ret = QWidget::event(event);
switch (event->type()){
case QEvent::Resize: {
auto e = reinterpret_cast<QResizeEvent*>(event);
{
SpinLockGuard guard(&d->mRenderLock);
d->mRenderSize = e->size();
if(mFirstResize) {
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->firstResizeEvent(e);
}
}
}
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->resizeEvent(e);
}
}
if(mFirstResize) mFirstResize = false;
}
markRenderStateDirty();
break;
}
case QEvent::Show: {
startRender();
break;
}
case QEvent::Hide: {
pauseRender();
break;
}
case QEvent::Enter: {
break;
}
case QEvent::Leave: {
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->setHoverState(QPoint(), false);
}
}
break;
}
case QEvent::Wheel: {
auto e = reinterpret_cast<QWheelEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->wheelEvent(e);
}
}
break;
}
case QEvent::MouseMove: {
auto e = reinterpret_cast<QMouseEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
bool selected = able->selectTest(e->pos());
able->setHoverState(e->pos(), selected);
if(selected) {
able->mouseMoveEvent(e);
}
}
}
break;
}
case QEvent::MouseButtonPress: {
auto e = reinterpret_cast<QMouseEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
if(able->selectTest(e->pos())) {
able->mousePressEvent(e);
}
}
}
break;
}
case QEvent::MouseButtonRelease: {
auto e = reinterpret_cast<QMouseEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
if(able->selectTest(e->pos())) {
able->mouseReleaseEvent(e);
}
}
}
break;
}
case QEvent::KeyPress: {
auto e = reinterpret_cast<QKeyEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->keyPressEvent(e);
}
}
break;
}
case QEvent::KeyRelease: {
auto e = reinterpret_cast<QKeyEvent*>(event);
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->keyReleaseEvent(e);
}
}
break;
}
default: break;
}
for(Layer* layer : mLayerList) {
for(RenderAble* able : layer->mRenderAbles) {
able->plotEvent(event);
}
}
return ret;
}
}