# MapLibreParticleLab 30_最小技术验证-02_GPU Ping-Pong 与 Context Recreation 验证指令书 v1 ## 1. 任务基本信息 - 项目:`MapLibreParticleLab` - 大阶段:`30_最小技术验证` - 子任务:`30-02 GPU Ping-Pong 与 Context Recreation 验证` - 当前主线:`particle/main` - 前置阶段: - `10_架构调查` 已完成 - `20_架构设计` 已完成 - `30-01 Core RenderLayer 接入验证` 必须已经正式 `PASS` - 前置正式架构文档: - `docs/10_架构/20_粒子系统总体架构设计_v1.md` - 任务性质:最小运行时技术验证 - 本任务不是正式粒子功能实现 - 本任务允许增加最少量、明确标记为 `VALIDATION ONLY` 的 GPU 验证代码 - 不允许顺手重构 MapLibre - 不允许扩大到真实 Particle Field、真实风/浪/潮/海流数据、Land/Ocean Mask、Vulkan 或 iOS 本任务不加入 Jest。 --- ## 2. 前置门槛 `30-02` 只能建立在 `30-01` 已经正式 `PASS` 的基础上。 Codex 开始前必须读取当前仓库中的: - `docs/60_测试/30_01_CoreRenderLayer接入最小技术验证报告_*.md` - `docs/报告/30_01_CoreRenderLayer接入验证_Codex完成报告_*.md` - `粒子开发记录.md` 并确认当前有效版本明确记录: `30-01 = PASS` 如果当前仓库仍然是: - `WAITING_MANUAL_VALIDATION` - `FAIL` - `BLOCKED` - 或无法找到正式 PASS 记录 则: 1. 不得开始 30-02 GPU 代码; 2. 不得自行把 30-01 改成 PASS; 3. 只生成阻塞说明; 4. 明确报告“30-02 前置条件未满足”; 5. 不提交任何 30-02 生产/验证代码。 用户当前已经明确要求进入 30-02,但最终仍以仓库中当前正式验证记录为执行门槛。 --- ## 3. 本任务为什么是 30-02 总体架构与 30-01 已经把最小技术验证顺序定义为: 1. Core RenderLayer / Style order / 同帧 Transform / repaint 2. GPU State A/B + Trail A/B ping-pong 与 context recreation 3. Camera / world wrap / Land-Ocean Mask 4. iOS Core Layer 薄接入 因此本任务只验证第 2 项。 本任务必须回答: > 已经通过 30-01 验证的独立 Core Particle RenderLayer,能否在 MapLibre 当前 gfx / RenderTarget / CommandEncoder 生命周期内稳定管理 GPU State A/B 和 Trail A/B,完成无读写冲突的 ping-pong,并在 viewport resize、Layer disable/enable、Surface/GPU context recreation 后正确释放和重建资源。 本任务不得提前处理第 3、4 项。 --- ## 4. 必须先读取 Codex 开始前必须完整读取: 1. 根目录 `AGENTS.md` 2. `PARTICLE_BASELINE.md` 3. `docs/00_项目总则/` 下当前全部有效文档 4. `docs/00_项目规范/` 下当前全部有效文档 5. `docs/20_调查/10_架构调查报告_v1.md` 6. `docs/10_架构/20_粒子系统总体架构设计_v1.md` 7. `docs/报告/10_架构调查_Codex完成报告_*.md` 8. `docs/报告/20_架构设计_Codex完成报告_*.md` 9. `docs/60_测试/30_01_CoreRenderLayer接入最小技术验证报告_*.md` 10. `docs/报告/30_01_CoreRenderLayer接入验证_Codex完成报告_*.md` 11. `粒子开发记录.md` 12. 30-01 当前实际验证代码 13. 与下列 gfx / GPU 资源链直接相关的当前源码: - `gfx::Context` - `Texture2D` - `DynamicTexture` - `RenderTarget` - `CommandEncoder` - render pass / upload pass - texture sampling / attachment 相关实现 - framebuffer / render target backend 实现 - Android OpenGL backend - EGL / surface / renderer context 生命周期 - resize / surface recreation 相关链 - 现有使用 offscreen RenderTarget 的 MapLibre 内部示例 - 现有 texture ping-pong、双缓冲或多 pass 示例,如仓库存在 不得根据通用 OpenGL 知识直接猜当前 MapLibre gfx 行为。 必须以当前 `particle/main` 实际代码为准。 --- ## 5. 开始前 Git 检查 先执行只读检查并记录: - 当前分支 - 当前 HEAD - `git status` - 当前公开远端 - `particle/main` 是否与远端同步 - 30-01 最终 PASS 对应 commit - 是否存在与本任务无关的本地修改 如果存在无关修改: - 不得删除 - 不得覆盖 - 不得一起提交 - 在完成报告中记录 - 本任务只 stage 本任务相关文件 如果当前不是 `particle/main`: - 不得擅自覆盖用户工作 - 先记录实际状态 - 不得为了完成任务强制 reset --- ## 6. 验证目标 本任务只回答下面五个问题。 ### V1. GPU State A/B 能否通过当前 gfx 资源体系建立并稳定 ping-pong 必须创建一组最小验证资源: - `State A` - `State B` 要求: - 两个资源在逻辑上独立 - 当前帧只读其中一个,只写另一个 - 帧结束后交换角色 - 下一帧反向读取/写入 - 不允许同一 pass 内把同一 texture 同时作为读取源和写入目标 - 不允许依赖 CPU 每帧搬运完整 state - 不允许依赖平台侧独立 GL 线程逻辑 本任务不冻结正式粒子状态 texture 的最终格式。 应优先选择当前 Android OpenGL + MapLibre gfx 已明确支持、便于验证的最小格式。 报告中必须明确: - 选择了什么 gfx texture / renderable resource - 为什么适合本次验证 - 哪些属性只是验证选择,不属于正式生产 contract --- ### V2. Trail A/B RenderTarget 能否稳定 ping-pong 必须创建: - `Trail A` - `Trail B` 基本要求: - Trail 使用真实 offscreen `RenderTarget` - 当前帧读取 previous trail - 写入 next trail - 完成后交换 A/B - 最后把当前有效 trail 合成到 MapLibre 正常主 render pass - 不覆盖地图正常 framebuffer 生命周期 - 不建立 MapView 外部 Overlay 本任务中的 Trail 只是验证图形。 允许使用: - 简单移动点 - 简单线段 - 简单 alpha 衰减 - 固定颜色图形 - 可重复确定性 pattern 禁止把本任务包装成正式风粒子视觉效果。 Trail 必须能够直观看出: - 前一帧结果被下一帧正确采样 - A/B 正在交替 - 不存在明显 feedback corruption - resize 后重新建立正确尺寸的 target --- ### V3. 多 Pass 同步 / hazard 是否能在现有 gfx 抽象内正确完成 必须确认实际执行顺序至少包含: ```text State Read → State Write → State swap → Trail Read → Trail Write → Trail swap → Composite to main render target ``` 实际顺序可根据当前 gfx API 调整,但必须满足无读写冲突。 重点调查并验证: - render pass 结束后下一 pass 采样刚写入资源是否成立 - 当前 gfx 是否自动处理必要状态切换 - Android OpenGL backend 是否依赖 pass ordering / framebuffer unbind / texture state - 是否存在显式 barrier API - 如果 OpenGL 路径不需要显式 barrier,必须如实记录,不得为了“看起来完整”自行增加无意义 barrier - 如果其他 backend 未来需要不同同步策略,应通过 gfx/backend 边界承载,不得把 GL/Vulkan/Metal 特例散到公共粒子逻辑 本任务要验证的是: > 当前 MapLibre gfx 抽象是否足够表达安全的 GPU ping-pong。 不是要求强行创造一套新的通用同步框架。 --- ### V4. resize / disable / enable 后资源生命周期是否正确 必须验证: #### viewport resize - Trail A/B 按新 viewport 尺寸重新创建 - 旧 Trail 资源被安全释放 - State A/B 如果与 viewport 无关,不得无意义重建 - resize 后第一帧状态明确 - 不采样已释放 target - 不出现黑屏、花屏或地图崩溃 #### Layer disable - 停止新增 GPU 更新 - 不继续无意义 repaint - GPU 资源如何保留或释放必须明确 - 行为应与总体架构生命周期一致 #### Layer re-enable - 如果资源仍有效,允许复用 - 如果已失效,必须重新创建 - ping-pong index / generation 必须恢复到明确状态 - 不允许使用旧 generation 的资源句柄 --- ### V5. Surface / GPU Context Recreation 后能否正确恢复 这是 30-02 的关键门槛。 必须调查当前 Android OpenGL 实际: - EGL context 生命周期 - SurfaceView / TextureView surface 生命周期 - renderer backend activate/deactivate - gfx context / resource 生命周期 - Activity background / foreground - Activity recreate - surface destroy / recreate 验证目标: 1. 能观察到一次真实的 surface/context/resource generation 变化; 2. 旧 State A/B、Trail A/B 不再被使用; 3. 新 GPU context/resource generation 中重新创建验证资源; 4. ping-pong 从明确初始状态恢复; 5. Trail 可以清空重新开始,不要求保留 context loss 前历史; 6. 地图本体继续正常工作; 7. 不 crash; 8. 不访问 stale texture / render target; 9. 不要求宿主重新创建第二套粒子 engine。 如果用户的普通后台/前台操作没有触发真实 GPU context recreation: - 不得把“Activity 回来了”当成 context recreation 已验证; - 必须通过日志或资源 generation 证明; - Codex 应基于当前 Test App / renderer 生命周期给出最小可重复触发方法; - 如果当前设备/虚拟机环境无法可靠触发,则该项标记 `BLOCKED` 或 `UNVERIFIED`,不得伪造 PASS。 --- ## 7. 验证代码必须保持最小 本任务不是正式 GPU Particle Simulation。 验证代码只需要证明: - gfx texture / renderable resource 可以建立 - State A/B 可以轮换 - Trail A/B 可以轮换 - pass 顺序正确 - resize 正确 - context recreation 正确 原则: > 能用一个极小 deterministic validation state 证明,就不要提前实现真实粒子状态。 推荐但不强制: - State texture:极小固定尺寸,例如 4×4、8×8 或 16×16 - State 内容:确定性递增值、位置标记或颜色编码 - Trail target:按 viewport 尺寸 - Trail 图形:简单移动 marker / alpha fade / pattern 最终尺寸和格式必须以当前 gfx 实际能力为准。 禁止因为方便直接引入第三方 GPU 库。 --- ## 8. State A/B 验证要求 至少记录逻辑: ```text frame 1: read=A, write=B frame 2: read=B, write=A frame 3: read=A, write=B ... ``` 必须验证: - A/B logical role 每帧交替 - swap 只在对应 pass 成功完成后发生 - pass 失败时不能错误推进 index - disable 后停止推进 - resource recreate 后 generation 增加并重置 index - 不跨 generation 复用逻辑引用 推荐内部验证元数据: - `resourceGeneration` - `frameIndex` - `stateReadSlot` - `stateWriteSlot` - `trailReadSlot` - `trailWriteSlot` - `viewportWidth` - `viewportHeight` 这些字段只用于验证,不代表正式公共 API。 --- ## 9. Trail A/B 验证要求 Trail A/B 必须真正经过 offscreen RenderTarget。 至少验证: 1. previous trail 被采样 2. 执行简单 fade / copy / pattern pass 3. 当前验证图元写入 next trail 4. next trail 成为新的 current trail 5. current trail 合成到地图 6. 下一帧角色交换 不得: - 直接在主 framebuffer 上画完后声称有 Trail ping-pong - 只创建两个 texture 但不实际作为 RenderTarget - 用 CPU image buffer 模拟 GPU trail resize 后: - old size target 必须退出 - new size target 必须建立 - 第一帧允许 clear - 不要求保留 resize 前 trail 历史 --- ## 10. gfx / backend 边界 公共验证逻辑必须优先使用当前 MapLibre gfx API。 禁止把下列调用散到 Core 粒子逻辑: - raw `glBindFramebuffer` - raw `glFramebufferTexture*` - raw `glMemoryBarrier` - raw Vulkan image barrier - raw Metal encoder 生命周期 如果当前 MapLibre gfx 缺少本验证不可绕过的能力: 1. 先确认仓库中确实不存在可复用抽象; 2. 只增加最小、粒子无关或 backend 合理归属的 gfx 扩展; 3. 不为未来猜测设计大型抽象; 4. 报告为什么必须新增; 5. 明确 Android OpenGL 与未来 Vulkan/Metal 的边界; 6. 如果必须大量侵入 gfx 通用架构,立即停止并标记架构阻塞。 --- ## 11. Shader 范围 本任务允许最少验证 shader,但必须明确标记: `VALIDATION ONLY` 允许: - copy - simple increment - fade - constant color - moving marker - simple composite 禁止: - 正式 velocity sampling - 正式 advection - respawn - random seed 系统 - 正式 particle age - 正式 field bounds - 正式 wind/current shader - Land/Ocean Mask - 正式颜色映射 - 正式产品参数 验证 shader 文件名也应明确体现 validation 属性。 --- ## 12. Context / Resource Generation 记录 为了避免把普通 lifecycle 误认为 context recreation,验证必须建立逻辑 generation。 例如: ```text ParticleGpuValidation: contextGeneration=1 resourceGeneration=1 create StateA create StateB create TrailA create TrailB ``` 发生真实 context/surface resource invalidation 后: ```text contextGeneration=2 resourceGeneration=2 create StateA create StateB create TrailA create TrailB ``` 不要求暴露底层 GL texture id。 如果当前 backend 能安全识别 context identity,可记录安全的调试信息。 如果不能: - 使用 renderer/backend lifecycle 事件 + resource generation 组合证明 - 不得为了日志强行暴露 backend 私有句柄 --- ## 13. 日志要求 日志必须足够判断 PASS/FAIL,但不能每帧爆量输出。 至少包含: - validation layer create - GPU validation resources create - resource generation - state A/B create - trail A/B create - first ping-pong frame - 每 N 帧一次: - frameIndex - state read/write slot - trail read/write slot - generation - resize detected - trail targets recreate - disable - enable - surface/context invalidation - resources destroy - resources recreate - first frame after recreation - validation layer destroy 建议每 60 帧或状态变化时输出一次。 禁止每帧完整输出 matrix、texture 描述或大量 GPU 状态。 --- ## 14. Android 第一验证平台 本任务第一运行平台固定为: **Android OpenGL** 不在本任务同时验证: - Android Vulkan - iOS OpenGL - iOS Metal 原因: 30-02 的目标是验证 Core gfx ping-pong 与资源生命周期这个架构门槛,不是一次完成所有 backend。 如果 Android OpenGL 证明当前 Core/gfx 路线本身无法成立,应先停止回到架构层,不得继续复制到其他平台。 --- ## 15. Android 编译规则:必须由用户手工执行 Codex 禁止运行 Android 编译。 禁止: - `./gradlew assemble...` - `./gradlew install...` - Android Studio build automation - 等价 Gradle Android build - 自动安装 APK Codex可以: - 修改验证代码 - 做静态源码检查 - 检查 CMake / Gradle 配置 - 给出用户手工编译命令 - 分析用户提供的编译错误 - 在本任务范围内修正代码 用户当前 Android OpenGL 构建基线已经采用仅 OpenGL 的目标。 Codex 必须根据当前实际 Gradle task 给出准确命令,不得凭旧命令猜测。 --- ## 16. ADB / 设备操作规则 Android 安装、启动和实体/虚拟设备验证由用户手工执行。 Codex 不得默认: - `adb install` - `adb shell am start` - 清 App 数据 - 自动抓 logcat - 自动重启设备 如需给出 ADB 命令,当前 MapLibreParticleLab / AutoNav Android 虚拟机地址固定为: `192.168.1.146` 所有命令必须显式使用: `adb -s 192.168.1.146 ...` 不得省略 `-s`。 不得使用旧地址 `192.168.200.145`。 --- ## 17. Test App 验证入口 优先复用 30-01 已建立并跑通的 Particle Core Layer Validation 入口。 不得为了 30-02 再建立一套完全平行的 Test App。 可以在现有验证 Activity / 页面中增加独立 GPU validation 模式或按钮,但必须: - 保持 30-01 原有验证能力不被破坏 - 明确区分 30-01 和 30-02 - 不让旧测试默认变成正式粒子 demo - 不引入产品 UI 建议提供最少控制: - `ACTIVE` - `STATIC` - `DISABLE` - `ENABLE` - `CLEAR/RESET`(如果确有必要) - 显示当前 generation / frame / ping-pong slots 具体形式以现有 Test App 结构为准。 --- ## 18. 用户手工验证步骤 Codex 阶段 A 完成后,必须给出准确、可直接执行的手工步骤。 至少覆盖: ### T1. 初始创建 观察: - State A/B 创建 - Trail A/B 创建 - generation 初值 - 首帧成功 ### T2. ACTIVE ping-pong 保持至少数十帧。 确认: - State A/B 持续交替 - Trail A/B 持续交替 - frame counter 增长 - 地图本身正常 ### T3. STATIC 确认: - ping-pong 停止推进 - 不继续由 validation layer 触发无意义帧 - 地图手势仍可触发正常 redraw ### T4. resize 执行当前设备环境下真实可行的 resize,例如: - 旋转屏幕 - 改变 Activity / window 尺寸 - 或当前 Test App 已有明确 resize 方法 确认: - Trail A/B 被重建为新尺寸 - State A/B 不发生无必要重建 - 地图正常 - 无 stale target ### T5. disable / enable 确认: - disable 后停止 - enable 后恢复 - generation/index 状态合理 - 无 crash ### T6. context / surface recreation Codex 必须根据当前 Android OpenGL backend 实际生命周期,给出能最大概率触发真实 recreation 的步骤。 可能包括但不限于: - Activity recreate - Surface destroy/recreate - 后台/前台 - 离开并重新进入验证 Activity 但最终判定必须看日志是否真正发生资源/context generation 变化。 仅“界面重新出现”不算通过。 ### T7. recreation 后继续运行 确认: - old resources destroy/invalid - new resources create - generation 增加 - ping-pong 重新正常工作 - Trail 从清空状态重新积累 - 地图无异常 --- ## 19. 两阶段执行方式 本任务继续采用 30-01 的两阶段方式。 ### 阶段 A:验证代码准备 Codex: 1. 检查 30-01 PASS 前置条件 2. 读取当前 gfx / Android OpenGL 生命周期 3. 设计最小验证实现 4. 写验证代码 5. 做静态检查 6. 生成暂定技术验证报告 7. 生成 Codex 完成报告 8. 追加开发记录 9. 给出用户手工编译/运行步骤 10. commit 11. push 到公开 `particle/main` 此时结论只能是: `WAITING_MANUAL_VALIDATION` 不得写 PASS。 --- ### 阶段 B:用户返回编译/运行结果后 Codex: 1. 读取用户提供的编译输出、日志和现象 2. 只修复 30-02 范围内的问题 3. 如果发现架构/gfx 路线本身失败,停止 4. 不通过扩大范围强行修成另一套架构 5. 更新技术验证报告 6. 更新 Codex 完成报告 7. 追加开发记录 8. commit 9. push 到公开 `particle/main` 最终只能是: - `PASS` - `FAIL` - `BLOCKED` --- ## 20. PASS 标准 只有同时满足以下条件,30-02 才能 PASS: - [ ] 30-01 当前正式状态为 PASS - [ ] State A/B 两套独立 GPU resource 成功建立 - [ ] State A/B 按帧安全交替 - [ ] 不发生同资源同时读写 hazard - [ ] Trail A/B 两套真实 RenderTarget 成功建立 - [ ] Trail previous → next 的 GPU pass 实际运行 - [ ] Trail A/B 按帧交替 - [ ] Trail 能合成回 MapLibre 正常主 render pass - [ ] 多 pass 顺序在当前 gfx 中稳定 - [ ] 当前 Android OpenGL 同步语义已被真实确认 - [ ] 不依赖 CPU 每帧复制完整状态 - [ ] 不依赖 MapView 外部 Overlay - [ ] 不建立平台独立动画循环 - [ ] resize 后 Trail target 正确重建 - [ ] disable 后停止无意义 GPU 更新 - [ ] enable 后可恢复 - [ ] 实际观察到资源/context generation 变化 - [ ] context/surface recreation 后旧资源不再使用 - [ ] recreation 后新资源重新建立 - [ ] recreation 后 ping-pong 恢复 - [ ] recreation 后 Trail 可重新开始 - [ ] MapLibre 地图渲染不被破坏 - [ ] 无 crash - [ ] 无明显 stale resource / framebuffer corruption - [ ] 未扩大到正式粒子算法、真实 Field、Mask、Vulkan、iOS - [ ] 未引入新第三方依赖 任何关键门槛缺少实际运行证据,不得标记 PASS。 --- ## 21. FAIL / BLOCKED 与停止条件 出现以下情况时停止继续向后实现。 ### F1. gfx 无法表达安全 ping-pong 如果必须绕开当前 gfx,在 Core 粒子逻辑中大量直接写 raw OpenGL 才能完成: - 停止 - 标记架构问题 - 不继续 30-03 ### F2. RenderTarget 无法作为下一 pass 的稳定采样源 如果当前架构下无法安全完成: `write → pass end → sample` 且无法通过很小的 gfx 合理扩展解决: - 停止 - 报告真实限制 ### F3. Context recreation 后存在 stale resource 如果旧 texture / render target 在新 context/resource generation 中仍被使用: - 30-02 FAIL - 不得忽略 crash 或图形损坏 ### F4. 必须把 GPU 生命周期放到 Android 平台层形成第二套 engine 如果 Core/gfx 无法共用,必须在 Android 独立维护完整 particle GPU engine: - 停止 - 回到架构设计 ### F5. 为了验证需要大规模修改 Renderer / Map 主循环 如果本验证迫使明显侵入: - Renderer 总体架构 - Map 主循环 - 通用 Layer 系统 - 大量 gfx backend 则停止,不得以“先能跑”为理由继续扩张。 ### B1. 无法触发真实 context recreation 如果代码本身运行正常,但当前测试环境无法可靠触发或确认真实 GPU context recreation: 最终状态应为: `BLOCKED` 不得写 PASS。 --- ## 22. 禁止事项 本任务禁止: - 正式 Particle Field - 正式 U/V Grid - fixture decode 正式实现 - velocity texture 正式 contract - 正式粒子 position / age / seed - 正式 advection - 正式 respawn - 正式 random 系统 - 正式风粒子效果 - Wave/Tide/Current 正式实现 - Land/Ocean Mask - world wrap 专项实现 - antimeridian 专项实现 - 真实天气/海洋服务 - Android Vulkan - iOS OpenGL - iOS Metal - RN/JS bridge - 新产品 API - 新第三方依赖 - MapLibre 版本升级 - Android SDK / NDK / Gradle 升级 - 与本任务无关的旧代码清理 - Jest --- ## 23. 允许修改范围 优先只修改: - 30-01 已建立的 Particle validation 相关 Core Layer / RenderLayer - 新增的 `ParticleGpuValidation*` 验证资源/辅助类 - validation-only shader - Android Test App 当前粒子验证入口 - 必要且最小的 gfx 接口扩展 - 本任务文档 - `粒子开发记录.md` 不得机械创建完整正式 particle production 目录树。 如果需要改动通用 gfx 文件: - 必须逐项列出 - 解释为什么现有 API 不足 - 保持修改最小 - 不得夹带重构 --- ## 24. 建议验证命名 优先使用: - `ParticleGpuValidationResources` - `ParticleGpuValidationPass` - `ParticlePingPongValidation` - `ParticleTrailValidation` - `ParticleGpuValidationShader` 或与当前仓库命名风格一致的等价名称。 所有临时代码应明确: `VALIDATION ONLY` 不得把未冻结代码命名为最终 `ParticleSimulation` / `ParticleTrailRenderer` 并假装已经生产化。 --- ## 25. 技术验证报告 生成: `docs/60_测试/30_02_GPU_PingPong与ContextRecreation最小技术验证报告_v1.md` 如果同主题已有文件: - 不覆盖 - 递增版本号 报告必须严格区分: 1. 静态源码确认 2. Codex 可确认的实现事实 3. 用户手工编译结果 4. 用户实际运行结果 5. 日志证据 6. 推论 7. 未验证项 阶段 A 时必须写: `WAITING_MANUAL_VALIDATION` --- ## 26. Codex 完成报告 生成: `docs/报告/30_02_GPU_PingPong与ContextRecreation验证_Codex完成报告_v1.md` 如果同主题已有报告: - 递增版本号 - 不覆盖旧报告 报告至少逐项说明: 1. 30-01 前置状态 2. 当前 Git 基线 3. 前置文档读取 4. 实际修改文件 5. State A/B 实现位置 6. Trail A/B 实现位置 7. RenderTarget 创建链 8. ping-pong swap 逻辑 9. pass 顺序 10. 同步 / hazard 处理 11. Android OpenGL backend 事实 12. resize 生命周期 13. disable/enable 生命周期 14. context/surface lifecycle 15. resource generation 机制 16. Test App 验证入口 17. 用户手工编译命令 18. 用户手工运行步骤 19. 当前验证状态 20. 是否修改通用 gfx 21. 是否修改生产代码 22. 是否引入依赖 23. 是否扩大范围 24. 未验证项 25. PASS / FAIL / BLOCKED 依据 26. 是否允许进入 30-03 27. Git commit 28. push 结果 29. 最终远端 HEAD --- ## 27. 开发记录 追加: `粒子开发记录.md` 必须记录: - 30-02 开始 - 30-01 前置状态 - State A/B 验证结论 - Trail A/B 验证结论 - gfx 同步结论 - resize 结论 - context recreation 结论 - 最终状态 - 是否允许进入 30-03 - 相关报告路径 不得重写已有历史。 --- ## 28. 不主动创建 Step 本任务不主动创建或修改: `docs/50_Step记录/` 只有用户明确要求时才创建 Step。 --- ## 29. Git 收尾规则 本任务只要产生代码或文档修改,就必须 commit 并 push。 目标: - 本地主线:`particle/main` - 公开远端对应分支:`particle/main` ### 29.1 提交范围 只允许提交: - 本任务验证代码 - 本任务 shader - 本任务 Test App 调整 - 本任务技术验证报告 - 本任务 Codex 完成报告 - 本任务对 `粒子开发记录.md` 的追加 不得提交与本任务无关的本地修改。 --- ### 29.2 阶段 A 提交 验证代码准备完成后: 1. 检查 `git diff` 2. 明确本任务文件列表 3. stage 本任务文件 4. commit 5. push 到公开 `particle/main` 6. 确认远端可见 推荐 commit message: `test: add particle gpu ping-pong validation` 阶段 A 报告状态必须仍为: `WAITING_MANUAL_VALIDATION` --- ### 29.3 阶段 B 提交 用户手工验证结果回填后: 1. 更新技术验证报告 2. 更新 Codex 完成报告 3. 更新开发记录 4. 如需修复,只修复 30-02 范围 5. commit 6. push 到公开 `particle/main` 7. 确认远端可见 推荐 commit message: `test: finalize particle gpu ping-pong validation` --- ### 29.4 Push 失败 如果 push 失败: - 不得声称完整完成 - 不得声称公开远端已经更新 - 完成报告必须写明: - push 失败 - 失败原因 - 本地 commit hash - commit message - 目标远端 - 目标分支 - 当前本地 HEAD --- ## 30. Git 信息记录 Codex 完成报告必须记录: - 任务开始 HEAD - 30-01 PASS commit - 本次主要变更 commit hash - commit message - push 是否成功 - 公开远端 - 远端分支 - push 后远端可见状态 - 最终远端 HEAD - 是否存在未提交的无关本地改动 为避免报告自引用 commit hash: - 完成报告中的“主要变更 commit hash”记录包含验证代码和主要文档的实质性提交; - 如果还有仅用于回填报告元数据的收尾 commit,Codex 最终回复中额外报告最终远端 HEAD; - 不得无限 amend 只为让报告包含自己的 commit hash。 --- ## 31. 30-03 进入条件 只有 30-02 最终状态为: `PASS` 才允许进入下一项最小技术验证。 下一项预计为: > Camera / world wrap / Land-Ocean Mask 最小技术验证。 如果 30-02 为: - `FAIL` - `BLOCKED` 则不得提前开始 30-03。 必须先处理 GPU/gfx/context 生命周期阻塞。 --- ## 32. 本任务完成定义 30-02 真正完成不是“创建了四个 texture”。 必须满足: > 在 Android OpenGL 的真实 MapLibre RenderLayer / gfx 渲染链中,已经通过用户实际运行证据确认:State A/B 与 Trail A/B 可以使用 MapLibre 当前 GPU resource / RenderTarget 体系安全 ping-pong;多 pass 顺序和同步语义成立;viewport resize 后资源正确重建;Layer disable/enable 生命周期正确;真实 surface/context/resource recreation 后旧资源不会被继续使用,新 generation 可以安全重建并恢复 ping-pong,同时不破坏地图正常渲染。 没有用户实际运行证据时,只能标记: `WAITING_MANUAL_VALIDATION` 真实 context recreation 无法验证时: `BLOCKED` 关键架构门槛失败时: `FAIL` 不得为了阶段推进把未验证结果写成 PASS。