Skip to content

Refactor viewer rendering architecture with MVVM pattern and add PAGX support#3356

Open
CodeJhF wants to merge 14 commits intomainfrom
feature/markffan_viewer_refactor
Open

Refactor viewer rendering architecture with MVVM pattern and add PAGX support#3356
CodeJhF wants to merge 14 commits intomainfrom
feature/markffan_viewer_refactor

Conversation

@CodeJhF
Copy link
Copy Markdown
Collaborator

@CodeJhF CodeJhF commented Apr 1, 2026

Viewer 渲染架构重构,将原有的 PAGView/PAGRenderThread 单一实现拆分为 ContentView/ContentViewModel/IContentRenderer 三层 MVVM 抽象,并在此基础上新增 PAGX 文件的完整渲染与编辑支持。

主要变更:

  1. 渲染架构重构(rendering/)

    • 新增 ContentView 基类、ContentViewModel 抽象接口、IContentRenderer 接口
    • 新增统一的 RenderThread,通过 IContentRenderer 委托格式特定渲染逻辑
    • PAG 渲染路径拆分为 PAGView / PAGViewModel / PAGRenderer
    • 新增 PAGX 渲染路径:PAGXView / PAGXViewModel / PAGXRenderer
    • PAGWindow 改为通过 ContentView 抽象连接 PAG 与 PAGX 的信号
  2. PAGX XML 源码编辑器(pagx/)

    • XmlLinesModel:行级 ListView 模型,支持大文件虚拟滚动
    • XmlSyntaxHighlighter:VS Code 暗色主题风格的 XML 语法高亮
    • XMLSourceEditor.qml:带行号、语法高亮、实时预览的 XML 编辑面板
  3. Profiler 扩展

    • 新增 PAGNodeStatsModel,按类别统计 PAGX 文档节点数量
    • PAGFileInfoModel / PAGRunTimeDataModel / PAGFrameDisplayInfoModel 增加 PAGX 支持
    • updateMetrics() 统一处理 PAG 逐帧指标与 PAGX 单帧指标
  4. 音频修复

    • 修复 buffer underflow 和 sample merging 缺陷
    • PAGAudioPlayer 改为从 AudioReader 获取 duration,移除对 PAGFile 的直接依赖
  5. Exporter 修复

    • EncodeAudioToMP4 改用系统临时目录路径,修复 Windows 非 ASCII 路径编码问题
  6. Bug 修复

    • 修复 PAGX 切换文件时图像消失问题
    • 修复 PAGXRenderer 中 lockContext 失败时的多余 device unlock 调用
    • 修复 setProgress 中 double 浮点相等比较导致进度更新被跳过的问题

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 1, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.55%. Comparing base (036f75e) to head (6c27124).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3356      +/-   ##
==========================================
+ Coverage   75.51%   75.55%   +0.03%     
==========================================
  Files         510      510              
  Lines       35435    35435              
  Branches    11283    11283              
==========================================
+ Hits        26760    26772      +12     
+ Misses       6362     6359       -3     
+ Partials     2313     2304       -9     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…guard, updateData frame bound check, PAGRenderer type safety, and MaxHighlightLength type.
Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review 总结

审查团队对本 PR 进行了全面的多维度代码评审,涵盖架构设计、线程安全、内存管理、性能、可维护性等方面。

共发现 1 个 Critical、5 个 High、8 个 Medium 级别的问题,详见各行级评论。

Critical

  • PAGView/PAGXView 析构顺序导致 use-after-free

High

  • PAGAudioRender::onWriteData 忙等待阻塞事件队列
  • PAGAudioReader::getDuration() 线程安全隐患
  • RenderThread::shutDown 遗漏 moveToThread 回迁
  • PAGViewModel::isPlaying_ 跨线程无同步
  • XmlSyntaxHighlighter 未处理跨行注释/CDATA

Medium

  • PAGViewModel::setProgress() 未加锁读取
  • PAGTreeViewModel beginResetModel 调用顺序错误
  • PAGXViewModel::loadFile Build 失败时状态不一致
  • PAGXViewModel::applyXmlChanges 未调用 updateAnimationState
  • XmlLinesModel maxLineWidth 只增不减
  • XmlLinesModel::data() 重复计算高亮
  • XmlSyntaxHighlighter 未闭合标签处理不完整
  • PluginInstaller 路径变更影响已安装用户

mutable std::mutex progressMutex = {};
int editableTextLayerCount = 0;
int editableImageLayerCount = 0;
bool isPlaying_ = false;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] 跨线程无同步:isPlaying_ 在主线程由 setIsPlaying() 写入,在 SceneGraph 线程由 flush()updatePaintNode() 通过 isPlaying() 读取,既非 atomic 也无锁保护,构成 C++ 数据竞争(UB)。建议改为 std::atomic<bool>。另外 mutable progressMutex 违反项目编码规范中「避免 mutable 声明变量」的要求,建议去掉 getProgress() 的 const。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。将 isPlaying_ 从普通 bool 改为 std::atomic<bool> 以保证线程安全,消除数据竞争。同时保持 mutable progressMutex 不变,因为 mutex 本身不是逻辑状态,是线程安全工具,这是规范的合理例外。

case PlainTextRole:
return line;
case HighlightedTextRole:
return XmlSyntaxHighlighter::highlightLine(line);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] 重复计算高亮:每次 ListView 滚动调用 data() 请求 HighlightedTextRole 都会重新执行 highlightLine()(正则匹配+HTML拼接),大文件快速滚动开销大。建议缓存高亮结果,仅在行内容变化时重新计算。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

已修复。新增 mutable std::vector<QString> highlightedLines 缓存高亮结果,data() 首次请求时计算并缓存,后续直接返回缓存值。修改行时自动清除缓存。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed: highlightedLines is now a lazy cache in data() — a highlighted string is computed once on first access and reused on subsequent calls. Cache entries are invalidated in setLineText() and cleared entirely in setContent()/clear(). The cache uses mutable because data() is a const virtual method required by QAbstractListModel; a comment has been added to explain this intentional exception to the project's mutable-avoidance guideline.

Comment on lines +125 to +132
fileInfos.emplace_back("Width", Utils::ToQString(static_cast<int>(pagxDocument->width)));
fileInfos.emplace_back("Height", Utils::ToQString(static_cast<int>(pagxDocument->height)));
fileInfos.emplace_back("Layers", Utils::ToQString(static_cast<int>(pagxDocument->layers.size())));
fileInfos.emplace_back("Nodes", Utils::ToQString(static_cast<int>(pagxDocument->nodes.size())));
fileInfos.emplace_back("Images", Utils::ToQString(CountImageNodes(pagxDocument)));
fileInfos.emplace_back("Version", QString::fromStdString(pagxDocument->version));
beginResetModel();
endResetModel();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以利用?:简化实现

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这是代码风格建议。当前实现清晰明确,已有两个明确的输出字符串(GetMemorySizeNumString / GetMemorySizeUnit)。为保持简洁性,暂不改用条件操作符。如果代码维护者有强烈偏好,后续可考虑。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review 第二轮 — 边界条件与架构设计

第二轮深度审查聚焦于第一轮遗漏的边界条件、竞态窗口、架构设计问题。

共发现 1 个 Critical、3 个 High、9 个 Medium 级别的新问题,详见各行级评论。

Critical

  • PAGAudioRender::Make 返回 nullptr 未检查,后续空指针崩溃

High

  • PAGAudioReader::setComposition 与 onRead 跨线程竞态
  • MainForm.qml hasPAGFile/hasAnimation 绑定在 Loader 切换期间可能访问已析构对象
  • PAGAudioRender 构造函数中 init() 在主线程创建 QAudioSink 但对象归属新线程,违反 Qt 线程模型

Medium

  • getCurrentFrame 在 totalFrames==0 时返回 -1
  • onAudioTimeChanged 中 duration==0 导致除零
  • progressPerFrame 在 frameRate/duration==0 时为 inf
  • refreshChartDataModel 中 vector 空时 size()-1 下溢
  • PAGWindow qobject_cast 类型分发违反开闭原则
  • ContentViewModel 基类包含格式专有纯虚方法
  • getPreferredSize 在两个 ViewModel 中逻辑完全重复
  • RenderThread::flush 中 view 裸指针可能指向已部分析构的对象
  • FileTreeViewDelegate 引用未声明的 selected 属性

CodeJhF added 5 commits April 8, 2026 14:45
…nents.

- PAGAudioReader::readNextSample: Added null check before accessing sample->time
- PAGAudioRender: Added null checks for audioOutput and audioDevice in onVolumeChange and onWriteData
- PAGAudioPlayer: Added initialization guards to prevent crashes when audio system fails to initialize
- PAGView: Fixed unsynchronized progress read that caused race condition in audio sync calculations
- XmlLinesModel: Added mutex protection for highlight cache to prevent multi-threaded races
…g mutable cache.

The mutex was added incorrectly under the assumption of multi-threaded access, but
QAbstractListModel::data() is always called from the UI thread. The mutable keyword
is retained with an explanatory comment since it is the standard pattern for lazy
initialization in a const virtual method required by Qt's model/view framework.
Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 0

}

double PAGXViewModel::getProgress() const {
return progress;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] progress 无锁保护,存在数据竞争:getProgress()setProgress()progress(普通 double)的读写无任何同步保护。PAGViewModel 已正确使用 progressMutex 保护同名变量,但 PAGXViewModel 遗漏了。在多核 CPU 上可能读到撕裂的 double 值。建议参照 PAGViewModel 使用 std::mutex 保护。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 1

Q_EMIT widthChanged(pagxWidth);
Q_EMIT heightChanged(pagxHeight);
Q_EMIT contentSizeChanged();
Q_EMIT pagxDocumentChanged(pagxDocument);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] 信号在锁外发射裸指针,存在生命周期风险:applyXmlChangesQ_EMIT pagxDocumentChanged(pagxDocument)renderMutex 锁外执行。如果另一个线程(如渲染线程通过 loadFile)在信号发射和接收之间替换了 pagxDocument,接收方持有的指针可能已失效。建议将 emit 移到锁内,或改用 shared_ptr 传递 document。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 2

}
}

void PAGAudioPlayer::setComposition(std::shared_ptr<PAGFile> pagFile) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] 双重启动风险:在已 playing 状态下切换 composition 时,不会先停止旧播放。旧 reader 的 onRead 回调可能正在执行,与新 composition 的初始化并发,读到部分初始化的数据。建议在 setComposition 前先停止当前播放(如先调用 audioRender->onSetIsPlaying(false) 并等待停止)。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 3

float offsetY =
(static_cast<float>(surfaceHeight) - static_cast<float>(state.contentHeight) * scale) *
0.5f;
auto matrix = tgfx::Matrix::MakeTrans(offsetX, offsetY);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] 变换矩阵计算属于 View 层职责,不应在 Renderer 中:每次 flush() 重新计算 contentLayer 的缩放居中变换矩阵,如果未来动画逻辑也修改矩阵会被覆盖。同时 Renderer 应只负责纯渲染。建议将此变换逻辑移到 PAGXViewPAGXViewModel 层。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 4

std::vector<QString> lines = {};
// mutable is intentional: highlightedLines is a lazy cache populated on demand inside the
// const data() method required by QAbstractListModel. All access is single-threaded (UI thread).
mutable std::vector<QString> highlightedLines = {};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[High] highlightedLines 缓存无容量限制,可能导致内存膨胀:对于大型 XML 文件(数千行),滚动浏览全部内容后缓存包含所有行的高亮 HTML 字符串(比原文大 3-5 倍),永不释放直到文件切换。建议设置容量上限(如 500 行覆盖典型视口 2-3 倍),或使用 LRU 淘汰策略。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 5

connect(viewModel, &ContentViewModel::filePathChanged, taskFactory,
&PAGTaskFactory::setFilePath);
}
if (auto* pagVM = qobject_cast<PAGViewModel*>(viewModel)) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] connectContentViewSignals 仍通过 qobject_cast 按类型 if-else 分发,新增内容类型必须修改此处,违反开闭原则。前两轮已提过此问题。建议在 ContentViewModel 基类中添加虚方法 connectExternalModels()/disconnectExternalModels(),让子类实现格式特定信号连接,PAGWindow 只调用基类方法。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 6

virtual QString getDisplayedTime() const = 0;
virtual QColor getBackgroundColor() const = 0;
virtual QSizeF getPreferredSize() const = 0;
virtual int getEditableTextLayerCount() const = 0;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] getEditableTextLayerCountgetEditableImageLayerCountgetShowVideoFrames 仅 PAG 格式有意义,PAGXViewModel 被迫实现返回 0/false。前两轮已提过此问题。建议改为带默认实现的虚方法:virtual int getEditableTextLayerCount() const { return 0; }

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 8


if (pagxDocument != nullptr) {
// Count nodes by category
std::unordered_map<QString, int> categoryCounts;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] std::unordered_map<QString, int> 使用 QString 作为 key,但 std::unordered_map 默认不使用 Qt 的 qHash,可能导致编译问题或性能下降。建议改用 QHash<QString, int>

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 9

int sampleRate) {
// Use a safe ASCII path in the temp folder to avoid encoding issues with non-ASCII characters
// on Windows, where FFmpeg may not correctly handle UTF-8 paths.
std::string mp4Path = JoinPaths(GetTempFolderPath(), ".pag_audio_temp.mp4");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] 两个问题:

  1. 临时文件名固定为 .pag_audio_temp.mp4,多进程并发导出时会互相覆盖。建议使用唯一文件名(如添加 PID 或时间戳后缀)。
  2. 多个提前返回路径(encoder/muxer 创建失败等)不会删除已创建的临时文件。建议使用 RAII 或 scope guard 统一清理。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 10

}

// Rebuild fullText from lines
QStringList lineList;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] 每次修改单行都重建整个 fullText(遍历所有行 + join),大文件(万行级别)下用户快速输入时会卡顿。建议延迟重建:用脏标记标记 fullText 已过期,仅在 allText() 被调用时才重建。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 11


void PAGAudioPlayer::setIsPlaying(bool isPlaying) {
Q_EMIT isPlayingChanged(isPlaying);
if (audioReader != nullptr || audioRender != nullptr) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] 条件 || 应为 &&:当 audioRender 为 nullptr(创建失败)但 audioReader 存在时,仍会发射 isPlayingChanged 信号,可能导致下游组件误认为音频正在播放。建议改为 if (audioReader != nullptr && audioRender != nullptr)

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 12


auto newContentLayer = pagx::LayerBuilder::Build(document.get());
if (newContentLayer == nullptr) {
return tr("Failed to build layer from XML document");
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] Build 失败时错误信息不具体:用户只看到泛化的错误提示,不知道具体哪一行、什么元素出错。对于 XML 编辑器场景,精确的错误位置信息对用户体验至关重要。建议如果 LayerBuilder::Build 能提供错误详情(行号、错误类型),应传递给错误信息。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 13

}

void PAGXViewModel::setProgress(double newProgress) {
if (std::abs(progress - newProgress) < 1e-9) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] setProgressprogress 的读写无锁保护。与行 50 的 getProgress() 同属一个问题:progress 作为普通 doublesetProgress()/getProgress() 中无同步,可能在 QML 绑定读取时与写入竞争。建议统一使用 std::mutexstd::atomic<double> 保护。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test comment 14


QVariantList PAGFrameDisplayInfoModel::getItems() const {
QVariantList list;
for (const auto& info : diplayInfos) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Low] 变量拼写错误:diplayInfos 应为 displayInfos(头文件 PAGFrameDisplayInfoModel.h:64 处声明,此处引用)。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

补充第三轮评审遗漏的一条评论。

start();
init();
QMetaObject::invokeMethod(this, "init", Qt::BlockingQueuedConnection);
isPlaying = true;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Medium] onSetIsPlaying()(行65-72)跨线程操作 audioOutput:该方法可从 UI 线程通过信号调用,直接操作 AudioRender 线程创建的 audioOutputresume()/suspend()),同时 onWriteData 在 AudioRender 线程也访问 audioOutput,存在竞态风险。此处 isPlaying = true 也是在主线程写入,而 onWriteData 中在另一个线程读取。建议确保相关信号连接使用 Qt::QueuedConnection,让 onSetIsPlaying 在 AudioRender 线程执行。

Copy link
Copy Markdown
Collaborator

@shlzxjp shlzxjp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review 第三轮 — 线程安全、架构设计与边界条件

第三轮深度审查由架构设计、线程安全、PAGX组件、音频/Profiler四个维度的专项评审组成。同时验证了前两轮所有问题的修复状态。

前两轮修复验证

前两轮共 30 个评论,所有 Critical/High 功能性和线程安全问题均已正确修复 ✅

本轮新发现

共发现 5 个 High、9 个 Medium、1 个 Low 级别的新问题,详见各行级评论。

High

  • PAGXViewModel::progress 无锁保护(数据竞争)
  • PAGXViewModel 信号在锁外发射裸指针
  • PAGAudioPlayer::setComposition 双重启动风险
  • PAGXRenderer::flush 变换矩阵属于 View 层职责
  • XmlLinesModel::highlightCache 无容量限制(内存膨胀)

Medium

  • PAGWindow 信号分发仍通过 qobject_cast(开闭原则)
  • ContentViewModel 纯虚接口过胖
  • PAGAudioRender::onSetIsPlaying 跨线程操作 audioOutput
  • PAGNodeStatsModel unordered_map 使用 QString 作 key
  • EncodeAudioToMP4 固定临时文件名+失败路径未清理
  • XmlLinesModel::setLineText 每次重建整个 fullText
  • PAGAudioPlayer::setIsPlaying 条件 || 应为 &&
  • applyXmlChanges Build 错误信息不具体
  • PAGXViewModel::setProgress 未同步保护

Low

  • PAGFrameDisplayInfoModel 变量拼写错误 diplayInfos

void PAGTree::buildTree() {
if (file == nullptr) {
return;
rootNode = nullptr;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rootNode看起来使用临时变量就可以了,不需要定义成类成员变量。

Comment on lines +65 to +66
const FrameDisplayInfo& imageDecode,
const FrameDisplayInfo& present) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

两个相同参数类型的不同变量交换了参数位置,要注意检查调用处是否都全部同步修改了


void PAGRunTimeDataModel::updatePAGXRenderTime(int64_t renderTime, int64_t imageTime,
int64_t presentTime) {
FrameDisplayInfo renderInfo("Render", "#0096D8", renderTime, renderTime, renderTime);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个颜色值在NodeColors中有定义过,可以改成map来映射颜色值

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants