鸿蒙PC迁移:RenderDoc 图形调试器鸿蒙PC适配全记录
一、写在前面
欢迎加入鸿蒙PC开发者社区,共同打造开发者工具生态:鸿蒙PC开发者社区:https://harmonypc.csdn.net/
项目开源地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_renderdoc
欢迎在PC社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper
这篇文章记录的是RenderDoc(v1.x)在 HarmonyOS PC / 鸿蒙真机环境中的一次适配过程。
RenderDoc 是图形开发者最常用的一款帧捕获式图形调试器:它把一帧里所有的渲染调用(draw call)整帧抓下来,然后离线回放,逐个事件检查 GPU 状态——查看纹理 / 渲染目标、检查每个 draw 的完整管线状态、调试着色器、查看顶点输入输出、做像素历史分析等等。原版支持 Vulkan、D3D11、D3D12、OpenGL / OpenGL ES、Metal,覆盖 Windows / Linux / Android。
原版 RenderDoc 是一个 C++ / Qt 桌面项目,主体由三块组成:图形 API 捕获 / 回放核心库librenderdoc、Qt Widgets 图形界面qrenderdoc、命令行工具renderdoccmd。它和 Electron 项目完全不一样,也不是 ArkUI 原生项目。和大多数 Qt 工具相比,RenderDoc 还有一个额外的硬约束——它的 GUI 强制内嵌 Python 解释器(通过一套自定义 SWIG 把整个回放 API 包装给 Python 用),这让它比普通 Qt Widgets 应用难移植得多。适配鸿蒙 PC 时,关键问题是:
- 怎样让一个 Qt Widgets 桌面程序进入鸿蒙 Stage 模型;
- 怎样让 native
libentry.so作为 HAP 的 native library 被 QPA 插件加载并启动; - 怎样让 Qt 界面绘制到鸿蒙 PC 窗口(XComponent)中;
- 怎样把 Qt for Harmony SDK、QPA 插件和 Qt 动态库打进 HAP;
qrenderdoc强依赖内嵌 Python + 自定义 SWIG + PySide2 +librenderdoc图形核心,这些在鸿蒙上都还没有,完整 GUI 怎么落地;- 怎样先做出一个可运行、可交互、长得像 RenderDoc 的鸿蒙 PC 版本。
这条路线的目标很明确:先把 RenderDoc 作为一个 Qt Widgets 应用稳定跑到鸿蒙 PC 真机上,复刻它的主界面布局并保证交互可用,再逐步评估完整qrenderdoc(内嵌 Python + SWIG 绑定 +librenderdoc核心)的深度迁移。
二、项目背景:RenderDoc 是 Qt/C++ 桌面应用
适配前先看项目性质。
RenderDoc 不是 Electron 应用,也不是 WebView 应用。它的主体是 C++ / Qt 桌面程序,原始桌面版本主要面向 Windows、Linux、Android。整个代码库大致分成几层:
- 捕获 / 回放核心:
renderdoc/(约 2000+ 头文件、800+ cpp),里面driver/下是各图形后端(d3d11 / d3d12 / gl / vulkan / metal)的 hook 与回放实现。这是 RenderDoc 的灵魂,也是最依赖具体平台和 GPU 驱动的部分。 - Qt Widgets 图形界面:
qrenderdoc/,所有面板(Texture Viewer / Pipeline State / Mesh Viewer / Event Browser / Python Shell 等)都在qrenderdoc/Windows/。 - 内嵌脚本层:
qrenderdoc通过CPython + 自定义 SWIG 分支 + PySide2/Shiboken,把整套回放 API 暴露给 Python,GUI 自身也依赖这层和核心通信。
这次适配新增的鸿蒙工程目录是:
renderdoc-1.x/ ├── renderdoc/ # 捕获/回放核心(保持不动) ├── qrenderdoc/ # Qt Widgets 界面(仅入口加一处 OHOS 守卫) ├── renderdoccmd/ # 命令行工具(保持不动) ├── CMakeLists.txt # 上游桌面构建(保持不动) └── harmony_pc/ # 鸿蒙侧新增工程,桌面构建完全不受影响 ├── AppScope/ │ └── app.json5 # bundleName: org.renderdoc.qrenderdoc ├── build-profile.json5 # app 级签名 / product 配置 ├── hvigorfile.ts / oh-package.json5 ├── qtforharmony_sdk -> ... # 工程自带的 Qt 5.15.12 for HarmonyOS(软链) └── entry/ ├── build-profile.json5 # externalNativeOptions -> CMake ├── libs/arm64-v8a/ # 打进 HAP 的 QPA 平台插件 .so └── src/main/ ├── module.json5 # deviceTypes: 2in1 / tablet ├── ets/ # ArkTS 桥 │ ├── abilitystage/MyAbilityStage.ets │ ├── entryability/EntryAbility.ets │ └── pages/Index.ets └── cpp/ ├── CMakeLists.txt # SHELL / FULL 双模式构建 └── renderdoc_ohos_shell.cpp # RenderDoc 界面外壳关键约束是:上游 RenderDoc 源码基本保持不动,所有鸿蒙相关的东西都放在harmony_pc/里,所以桌面构建完全不受影响。唯一一处改动是给qrenderdoc/Code/qrenderdoc.cpp的main()加了一个Q_OS_OPENHARMONY守卫的qtmain别名(为将来的 FULL 构建预留,桌面路径不变)。
当前适配里最核心的文件是:
harmony_pc/entry/src/main/cpp/renderdoc_ohos_shell.cpp # Qt Widgets 界面外壳 harmony_pc/entry/src/main/cpp/CMakeLists.txt # SHELL / FULL 双模式构建 harmony_pc/entry/build-profile.json5 # CMake 参数 / abiFilters harmony_pc/AppScope/app.json5 # 包名与应用信息三、路线选择:借鉴已有 Qt for Harmony 工程的启动管线
适配 RenderDoc 时,参考了之前几个 Qt → HarmonyOS 工程:ok-minitube-master、ok-Natron-ohos、ohos_avogadrolibs、ok-krita-ohos。
这里要特别区分:参考的是这些项目的Qt for Harmony SDK、Stage 工程组织方式和 native Qt 启动管线,而不是把它们的业务代码拿来跑。最终真机上安装的包始终是 RenderDoc:
bundleName: org.renderdoc.qrenderdoc Ability: EntryAbility Module: entryAppScope/app.json5中应用信息配置为:
{ "app": { "bundleName": "org.renderdoc.qrenderdoc", "vendor": "baldurk", "versionCode": 1000000, "versionName": "1.0", "icon": "$media:layered_image", "label": "$string:app_name" } }鸿蒙工程的设备类型面向 PC / 平板:
"deviceTypes": [ "2in1", "tablet" ]Qt SDK 通过entry/build-profile.json5的 CMake 参数传入:
"externalNativeOptions": { "path": "./src/main/cpp/CMakeLists.txt", "arguments": "-DQT_PREFIX=qtforharmony_sdk -DRENDERDOC_FULL_APP=AUTO", "cppFlags": "", "abiFilters": ["arm64-v8a"] }这里QT_PREFIX=qtforharmony_sdk是相对路径,CMake 里会把它解析成harmony_pc/qtforharmony_sdk的绝对路径,并校验lib/cmake/Qt5/Qt5Config.cmake是否存在。这一点是整个适配能跑起来的基础——QT_PREFIX必须指向 Qt for Harmony SDK,否则 CMake 找不到Qt5Config.cmake、Qt Widgets 和 QPA 平台插件。工程用的是Qt 5.15.12 for HarmonyOS(arm64-v8a,OHOS SDK 18);这个 SDK 体积约 295MB,所以harmony_pc/qtforharmony_sdk用的是指向共享 SDK 的软链接,避免把它塞进仓库(CI / 移植到别的机器时换成真实拷贝即可)。
另一个关键参数是RENDERDOC_FULL_APP,它决定了构建模式(这是这次适配的核心设计):
| 模式 | 取值 | 编译什么 | 状态 |
|---|---|---|---|
| SHELL | AUTO/OFF(默认) | 只编renderdoc_ohos_shell.cpp——一个自包含的 Qt Widgets 界面外壳,只链接 Qt5 Core/Gui/Widgets/Svg/Network/Concurrent/OpenGL,不依赖 librenderdoc / Python / SWIG | ✅ 可运行 |
| FULL | ON | 编真实的qrenderdoc+librenderdoc。需要先把CPython、SWIG 绑定、librenderdoc交叉编译到 OpenHarmony,目前缺这些前置条件,CMake 会带提示直接报错 | 🚧 阻塞中 |
AUTO会探测两个 FULL 模式的前置产物是否存在——harmony_pc/python-ohos/lib/libpython3.so和harmony_pc/librenderdoc-ohos/lib/librenderdoc.so——不存在就自动回退到 SHELL,所以 HAP 永远能构建、能启动。
本次选择的第一阶段路线是:
- 不重写 ArkUI 主界面;
- 不一次性迁内嵌 Python、SWIG 绑定和 librenderdoc 核心;
- 先用 Harmony Stage 工程承载 Qt Widgets;
- 用 C++ 写一个自包含的界面外壳 SHELL,复刻 RenderDoc 主窗口布局,绕过 Python / 图形核心;
- 真机验证窗口、菜单 / 工具栏、面板切换、事件树、纹理通道、缩放等交互;
- 再根据后续目标决定是否继续迁 Python + SWIG + 核心。
这条路线适合快速验证 Qt 桌面工具在鸿蒙 PC 上的窗口、输入、构建、安装和运行链路。
四、鸿蒙工程壳:Stage Ability + XComponent + QPA → libentry.so
鸿蒙侧仍然是标准 Stage 工程。整条启动管线是这样串起来的:
HarmonyOS 启动 org.renderdoc.qrenderdoc(EntryAbility) -> EntryAbility.onWindowStageCreate() 加载 pages/Index -> Index.ets 构建一个 XComponent(libraryname: plugins_platforms_qopenharmony) -> EntryAbility 调用 qpa.startQtApplication(this) -> QPA 插件在 XComponent 上创建绘制表面,并 dlopen() libentry.so -> 解析 libentry.so 导出的 extern "C" qtmain -> qtmain -> main() -> QApplication -> RenderDoc 主窗口渲染进这个表面Index.ets里的核心就是一个XComponent,它的libraryname指向 QPA 平台插件:
XComponent({id:this.windowId,type:XComponentType.NODE,libraryname:'plugins_platforms_qopenharmony'}).width('100%').height('100%');MyAbilityStage.ets在工程启动时把 QPA 插件挂上去,并通过onAcceptWant返回主窗口实例 key:
onCreate():void{qpa.attachAbilityStage(this);}onAcceptWant(want:Want):string{// 首次启动返回 renderdoc_main_window...}EntryAbility.ets在窗口 stage 创建后,真正拉起 Qt 应用:
importqpafrom'libplugins_platforms_qopenharmony.so';asynconWindowStageCreate(windowStage:Window.WindowStage){...awaitthis.launchParamSet();// 可把 .rdc 抓帧文件路径作为 argv[1] 传进去this.startQtApplication();}privatestartQtApplication(){qpa.startQtApplication(this);// QPA 插件随后 dlopen libentry.so 并调用 qtmain}native 侧的CMakeLists.txt把入口编译成entry(即libentry.so)。SHELL 模式下只编一个源文件:
add_library(entry SHARED "${CMAKE_CURRENT_SOURCE_DIR}/renderdoc_ohos_shell.cpp") target_compile_features(entry PRIVATE cxx_std_17) target_compile_definitions(entry PRIVATE APP_NAME="RenderDoc" OPENHARMONY NAPI_DISABLE_CPP_EXCEPTIONS) set_target_properties(entry PROPERTIES BUILD_RPATH "$ORIGIN") target_link_libraries(entry PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Svg Qt5::Network Qt5::Concurrent Qt5::OpenGL)这里有一个踩过的坑写进了注释:链接Qt5::Gui会让 hvigor 的collectAllLibs把 Qt 的图片格式插件(qgif/qico/qjpeg/qsvg)一起打包,而 qsvg 插件又依赖libQt5Svg.so,所以必须同时链接Qt5::Svg,否则 QPA 插件加载libentry.so时会失败,真机上表现为白窗口。另外 QPA 平台插件本身是被 ArkTS 加载的,不需要在这里链接。
C++ 入口通过导出的qtmain被 QPA 插件调用:
intmain(intargc,char**argv){QApplicationapp(argc,argv);app.setApplicationName(QStringLiteral("RenderDoc"));app.setStyleSheet(QString::fromUtf8(kStyle));// RenderDoc 风格深色主题QMainWindow window;// ... 搭建 Event Browser / Texture Viewer / Pipeline State / ...window.showMaximized();returnapp.exec();}#ifdefined(Q_OS_OPENHARMONY)// Qt OpenHarmony 平台插件 dlopen() libentry.so 后调用 "qtmain"extern"C"intqtmain(intargc,char*argv[]){returnmain(argc,argv);}#endif五、SHELL 界面外壳:先做可运行的 MVP
完整qrenderdoc+ Python + 核心库的迁移不是第一阶段目标。为了先把真机可用链路跑通,这次实现了一个自包含的 Qt Widgets 界面外壳renderdoc_ohos_shell.cpp,复刻 RenderDoc 主窗口的布局和外观。
它的主窗口是一个标准QMainWindow:顶部菜单栏 + 工具栏,中间用QSplitter三栏布局,底部状态栏。当前 SHELL 外壳的界面包括:
- 菜单栏:File(Open Capture / Save Capture / Exit)、Window、Tools、Help;
- 工具栏:RenderDoc 橙色品牌名 + Capture / Open Capture / Save + 右侧绿色 API 按钮;
- 左栏 Event Browser:事件树(Frame #1024 → Shadow Pass / GBuffer Pass / Lighting Pass / Post + Present,带 EID 列),上方有过滤框;
- 中栏分析标签页:
- Texture Viewer:棋盘格背景 + 自绘渐变纹理画布、RGBA 通道开关、Mip / Zoom 下拉、底部输出缩略图条;
- Pipeline State:VTX→VS→HS→DS→GS→RS→PS→OM→CS 管线阶段按钮 + 资源/状态表;
- Mesh Viewer:顶点输入表(VTX / IDX / POSITION / NORMAL / TEXCOORD);
- Python Shell:控制台预览(真实交互式控制台需要内嵌 CPython,见第六节);
- 右栏 Inputs / Outputs:绑定的输入资源与渲染目标列表;
- 状态栏:显示当前加载的抓帧、EID 等信息。
整个外壳是 UI 演示性质:它不链接 librenderdoc,也不做真实抓帧 / 回放,目的是把鸿蒙启动链路(ArkTS → XComponent → QPA →libentry.so→qtmain→ 可见且可交互的 Qt 窗口)端到端跑通,并在真实qrenderdoc落地前先占位。
六、为什么先做 SHELL,而不是完整 qrenderdoc
这是 RenderDoc 适配里最需要解释的一个决策,也是它和别的 Qt 工具最不一样的地方。
普通 Qt Widgets 工具,把界面源码编进libentry.so、链接 Qt SDK 基本就能跑。但RenderDoc 的 GUI 不行——qrenderdoc/Code/qrenderdoc.cpp的main()直接#include "pyrenderdoc/PythonContext.h",也就是说:
- GUI 强制内嵌 Python 解释器(CPython);
- 一套RenderDoc 自定义的 SWIG 分支在构建时生成 C++↔Python 绑定,把整个回放 API 包装给界面用——这些绑定不是可选项,而是 GUI 和核心通信的桥;
- 可选还要PySide2 / Shiboken(让 Python 能操作 Qt 对象);
- 最终还要链接
librenderdoc(捕获 / 回放核心)。
而本地目前没有为 OpenHarmony 交叉编译的 Python,没有 OHOS 版 SWIG,工程自带的 Qt SDK 里也不含 PySide / Shiboken。直接编完整qrenderdoc是过不去的,需要一条多阶段的前置链路(已核实的“必做清单”):
- 为 arm64-ohos交叉编译 CPython,产出
libpython3.so和头文件; - 在构建主机上跑RenderDoc 自定义 SWIG生成
*_python.cxx绑定(这步在主机跑,不在目标设备),再用上一步的 OHOS Python 编译; - 为 OpenHarmony交叉编译
librenderdoc(先做回放侧,Vulkan/GLES 捕获 hook 是强平台相关的,留到后面); - PySide2 可先用
QRENDERDOC_ENABLE_PYSIDE2=OFF关掉(只丢 Python 操作 Qt 的能力,Python 控制台本身还在)。
为了先让应用跑起来、可演示,SHELL 直接绕开了这一整套:用纯 Qt Widgets 复刻界面,不需要任何 Python / SWIG / 核心库就能在真机上交互运行。这和 Avogadro 适配里“先用 QPainter CPU 渲染绕开 OpenGL ES 移植”是同一种“先能跑、再优化”的工程取舍——Python + SWIG + 核心的深度迁移留给后续阶段。
七、真机调试踩的两个坑
外壳第一版装到真机后,连续踩了两个很典型的坑,都和“鸿蒙上的 Qt 行为”有关,记录下来。
坑 1:缩放后文字 / 内容不放大也不缩小。改鸿蒙系统 / 窗口缩放比例时,界面内容纹丝不动。原因是 Qt 默认按 device-pixel-ratio = 1 渲染,没启用高 DPI 缩放。修复办法是在QApplication构造之前打开高 DPI 属性(注意顺序,构造之后再设就无效了),并用PassThrough让 1.25 / 1.5 这类小数倍率也生效:
#if(QT_VERSION>=QT_VERSION_CHECK(5,14,0))QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);#endifQApplication::setAttribute(Qt::AA_EnableHighDpiScaling);QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);QApplicationapp(argc,argv);// 必须在属性设置之后构造坑 2:点任何按钮都没反应。这个不是鸿蒙输入问题,而是第一版外壳是按“静态界面预览”写的,绝大多数控件没有连接槽函数——只有菜单 Exit、可勾选按钮的勾选态、标签页切换是默认能动的。判断依据是:参考的 minitube 是个能正常点击的真实应用,用的是完全相同的 XComponent 接法,说明输入链路本身是通的,缺的只是处理逻辑。修复办法是给每个可交互控件都接上可见反馈:工具栏 / 菜单 → 状态栏提示;RGBA 通道按钮 → 真正改变纹理画布;事件树点击 → 显示 EID 并更新画布标题;API 按钮 → 在 Vulkan / D3D11 / D3D12 / OpenGL 间循环;Mip / Zoom 下拉、列表点击、Python 输入框回车都给反馈。
这两个坑也顺带说明了一件事:真机上验证“缩放 + 点击”是判断 Qt 应用是否真正活起来的最快方式。
八、构建、安装和真机运行
本次工程路径:
/XM/renderdoc-1.x/harmony_pc构建时需要指定 DevEco SDK 环境变量,否则可能遇到 hvigor / SDK 版本不匹配问题,例如:
(0 , hvigor_1.WithParamReplacement) is not a function最终使用的构建命令是:
cd/XM/renderdoc-1.x/harmony_pcenvDEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk\OHOS_BASE_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony\/Applications/DevEco-Studio.app/Contents/tools/node/bin/node\/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw.js\--modemodule-pmodule=entry-pproduct=default assembleHap\--analyze=normal--parallel--incremental--no-daemon--stacktrace注意:首次在 DevEco Studio 打开
harmony_pc/时,需要为org.renderdoc.qrenderdoc这个包名配置签名(签名 profile 是和包名绑定的,不能复用别的工程的签名)。
native 部分的 CMake 构建由entry/build-profile.json5 → externalNativeOptions驱动,会把-DQT_PREFIX=qtforharmony_sdk -DRENDERDOC_FULL_APP=AUTO传给CMakeLists.txt,只编 arm64-v8a。
签名后的 HAP 路径:
harmony_pc/entry/build/default/outputs/default/entry-default-signed.hap安装到真机:
/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdcinstall-r\/XM/renderdoc-1.x/harmony_pc/entry/build/default/outputs/default/entry-default-signed.hap启动应用:
/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc shell aa start\-borg.renderdoc.qrenderdoc\-aEntryAbility强停应用:
/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc shell aa force-stop org.renderdoc.qrenderdoc查看安装信息(确认包名 / ABI / SDK 版本):
/Applications/DevEco-Studio.app/Contents/sdk/default/openharmony/toolchains/hdc shell bm dump-norg.renderdoc.qrenderdoc关键输出应包含:
bundleName: org.renderdoc.qrenderdoc versionName: 1.0 cpuAbi: arm64-v8a九、真机验证流程
最终真机验证按下面这条路径走:
安装 HAP -> 启动 RenderDoc(aa start) -> 默认显示 Event Browser + Texture Viewer -> 点左侧 Event Browser 的事件(如 EID 142)-> 观察底部状态栏更新 -> 点中间标签页切到 Pipeline State / Mesh Viewer -> 在 Texture Viewer 里点 R / G / B / A 通道开关 -> 看纹理画布颜色变化 -> 点右上角 API 按钮 -> 在 Vulkan / D3D11 / D3D12 / OpenGL 间切换 -> 改系统 / 窗口缩放比例 -> 看文字和面板是否跟着放大缩小切换标签页和点击事件树是验证“面板交互 + 状态更新”是否正常的最直接方式;RGBA 通道开关、API 按钮和缩放则验证鼠标事件、重绘和高 DPI 是否都正确传到了 Qt 窗口。
十、当前版本边界和后续方向
这次适配完成的是 RenderDoc 在鸿蒙 PC 真机上的第一阶段可运行版本(SHELL)。它已经解决了几个关键问题:
- HarmonyOS Stage 工程接入;
- 工程自带 Qt for Harmony SDK(Qt 5.15.12 / arm64-v8a)接入;
- ArkTS → XComponent → QPA →
libentry.so→qtmain的完整启动管线; - Qt Widgets native 应用启动与窗口显示;
- 链接
Qt5::Svg解决 qsvg 插件依赖导致的白窗口问题; - 高 DPI 缩放(内容随系统缩放放大 / 缩小);
- 全界面交互(菜单 / 工具栏 / 事件树 / 标签页 / 纹理通道 / API 切换);
- RenderDoc 包名和应用信息替换;
- HAP 构建、签名、安装;
- 用纯 Qt Widgets 外壳绕开 Python / SWIG / 核心移植,先把应用跑起来。
后续方向(roadmap):
- Phase 2 — 交叉编译 Python-for-OHOS:为 arm64-ohos 编出
libpython3.so+ 头文件,放到harmony_pc/python-ohos/,这是 FULL 模式的第一个硬阻塞。 - Phase 3 — 生成 SWIG 绑定并接核心:在主机上跑 RenderDoc 自定义 SWIG 生成绑定,交叉编译
librenderdoc(先回放侧)到harmony_pc/librenderdoc-ohos/;两个前置产物就位后,RENDERDOC_FULL_APP=AUTO会自动从 SHELL 切到 FULL。 - Phase 4 — 捕获后端(可选 / 长期):评估在鸿蒙上做 Vulkan / GLES 的捕获 hook,让 RenderDoc 不只是回放别处抓的
.rdc,还能直接抓鸿蒙本机应用的帧。
十一、总结
这次 RenderDoc 适配不是一次简单的套壳,也不是 Electron 项目的资源搬运。它更接近一次 Qt 桌面工具在鸿蒙 PC 上的 native 运行验证,而且因为 RenderDoc 的 GUI 强制内嵌 Python + 自定义 SWIG,它比一般 Qt Widgets 工具更能体现“依赖链很深的桌面工具,在鸿蒙上要怎么分阶段落地”这个现实约束下的工程取舍。
整个过程可以概括为:
识别原项目技术栈(Qt Widgets + 内嵌 Python/SWIG + librenderdoc 图形核心) -> 新增 harmony_pc Stage 工程,上游源码基本保持不动 -> CMake 接入工程自带 Qt for Harmony SDK(Core/Gui/Widgets/Svg/Network/Concurrent/OpenGL) -> 设计 SHELL / FULL 双模式,先编可运行的 SHELL -> 用纯 Qt Widgets 外壳绕开 Python / SWIG / 核心移植 -> 修高 DPI 缩放 + 补全控件交互 -> 替换包名和应用信息 -> 构建签名 HAP -> 安装到鸿蒙 PC 真机验证界面与交互最终结果是,一个以org.renderdoc.qrenderdoc为包名的 RenderDoc Harmony PC 应用,可以在真机上启动、显示出 RenderDoc 的主界面布局(Event Browser / Texture Viewer / Pipeline State / Mesh Viewer),并支持菜单、工具栏、事件树、标签页切换、纹理通道开关、API 切换和高 DPI 缩放等完整交互。虽然它还不是完整上游 RenderDoc(内嵌 Python、SWIG 绑定与 librenderdoc 核心仍在迁移中),但已经具备了第一阶段可运行、可演示、可继续扩展的基础。
