feat: draw all raster particle states
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled

This commit is contained in:
OpenAI Codex
2026-09-03 15:04:05 +08:00
parent c0d1ad43c4
commit a0aae48ec8
7 changed files with 277 additions and 8 deletions

View File

@@ -0,0 +1,37 @@
# STEP-044 Android OpenGL 粒子数量容量基线 v2
- 状态:`IMPLEMENTED / WAITING FOR ANDROID VALIDATION`
- 基线:`c0d1ad43c49ed6d526c3fd8b982c04840326d0d0` 的容量档位实现。
- 范围:补齐正式 RasterParticle 的 full particle draw;不是新 Step,也不是容量结论或性能优化。
## v1 的实际缺口
v1 已让 State A/B 容量随 `raster-particle-particle-count` 改为 256 至 1,048,576,但 Trail fragment 只读取四个固定 State UV。因此当时只能证明 N 个 State 同时 simulation,不能证明 N 个粒子同时 Trail/render/composite;Android 容量验收据此暂停。
## v2 补齐
- `effectiveParticleCount=N -> State N -> Trail draw N -> Composite` 已进入唯一正式 `RasterArraySource -> RasterParticleLayer -> RenderRasterParticleLayer` 链。
- 每个粒子在 State A/B 中对应一条静态 GPU vertex:`particleIndex -> x=index%stateGridWidth, y=index/stateGridWidth`。vertex buffer 仅在 resource create 或 particle-count change 重建;顶点 shader 用 `(x+0.5,y+0.5)/stateGrid` 采样当前 State write texture,位置从未 CPU 生成或 readback。
- Trail write target 先由全屏 Trail fade quad 消费前一 Trail,再追加 full point draw。每粒子一个 point,`trailDrawCount=N`;Composite 继续消费同一 Trail A/B write target。
- 现有 16-bit index 路径每 segment 最多 65,536 points;更高 count(包括 1M)被分为多个 segment,仍使用同一 static index buffer、同一 shader 和同一 State texture,非第二 simulation。
- legacy `ParticleValidationLayer` 仍保留四个 deterministic sample 诊断;正式 RasterParticle Layer 的路径不再使用它们作为 draw 数量限制。
## 生命周期与冻结语义
- particle-count change 继续只触发合理的 State A/B 和 full-draw resource rebuild,以及 `SIMULATION_RESET reason=PARTICLE_COUNT_CHANGE` / reseed。
- Field T0/T1、MIX、interpolation、Field reuse、mask、A/B→B/C 及既有 State/Trail ping-pong 没有改变。MIX 仍不能导致 draw resource rebuild、Style reload、Field upload 或 reset。
- State seed 仍是每个 State texel 的 `v_uv`,所以 full draw 的首次 256/1K 粒子已经 deterministic 地分布在完整 grid,而非重叠于一个点。
## 观测日志
资源 create/rebuild/release 日志含 `effectiveParticleCount`、`stateGrid`、`trailDrawCount`、`particleIndexCount`、`fullParticleDraw=true` 和 `resourceGeneration`。`PARTICLE_DRAW_REJECTED` 明确报告缺失 draw resource 或 drawable finalize failure。
## 待 Android 验收
| 用例 | 要求 | 状态 |
|---|---|---|
| T-FULL-01 | 256:`16x16`、`trailDrawCount=256`、明显粒子群并持续运动 | 待测 |
| T-FULL-02 | 1K:`32x32`、`trailDrawCount=1024`、密度明显大于 256、Trail/Composite 正常 | 待测 |
| T-FULL-03 | 256→1K→256:draw count 同步变化,无 crash、Style reload、Field upload 或 MIX 改变 | 待测 |
只有 T-FULL-01~03 通过,才恢复 4K / 16K / 64K / 1M 的容量矩阵。Codex 未运行 Android Gradle、ADB、安装或设备测试;未加入 Jest。

View File

@@ -0,0 +1,42 @@
# 40-03 Android OpenGL 粒子数量容量基线 Codex 完成报告 v2
## 状态
`40-03:IMPLEMENTED / WAITING FOR ANDROID VALIDATION`
v1 的 Android 容量验证暂停是正确的:它的 State A/B 已支持 N 个状态,但 Trail/render 只消费四个固定 State sample。本次补齐后尚无 Android 实机证据,不能写 `CLOSED / PASS`。
## 已完成
1. 原固定 sample 位于 `shaders/particle_gpu_validation.fragment.glsl` 的 Trail 分支,固定 State UV 为 0.125、0.375、0.625、0.875;原 Trail 实际是一个全屏 quad,6 个 index,并非 N 个粒子 draw。
2. 正式 full draw 采用静态 State-index vertex buffer,而不是 GPU instance ID:每个 index 一次性映射到 `(x=index%width, y=index/width)`,数目等于 `effectiveParticleCount`。它在初始资源创建和 count rebuild 创建/释放,稳定帧不做 CPU 粒子循环。
3. formal Trail pass 先用既有全屏 quad 衰减 previous Trail,随后以 `gfx::Points` 提交所有 static State index。vertex shader 从当前 State write texture 读取该 index 的 RG position;每个 point 进入同一 Trail A/B target,Composite 无改动地读取 Trail write。
4. 256 时 `trailDrawCount=256`;1K 时 `trailDrawCount=1024`。1M 使用相同机制,按最多 65,536 points 的 16-bit-index segment 切分为多个 draw segment,理论路径为 1,048,576 State texel / point draw。
5. 固定四 sample 仅保留给 legacy `ParticleValidationLayer` 诊断。正式 RasterParticle Layer 不再依赖它们;没有 GPU→CPU readback、每帧 CPU position 生成、旁路 overlay 或第二 simulation。
6. State seed 保持每个 State texel 的 `v_uv`,无需改变 reseed;每粒子初始位置已是 deterministic grid-distributed。没有修改 U/V、`dy=-v`、Field sampling、T0/T1、MIX、JNI 或 40-02 resource identity 语义。
7. `PARTICLE_DRAW_RESOURCES_CREATE|REBUILD|RELEASE` 与 `PARTICLE_DRAW_REJECTED` 日志新增/补齐 `effectiveParticleCount`、`stateGrid`、`trailDrawCount`、`particleIndexCount`、`fullParticleDraw=true` 和 generation。
## 本地检查
- shader generator 连续两次运行,生成物稳定;源 GLSL 是唯一修改入口。
- Linux/OpenGL 精确编译通过:`render_particle_validation_layer.cpp.o`、`raster_particle_layer.cpp.o`、`style_layer.test.cpp.o`。
- 相关 Layer test object 已编译;完整测试二进制当前 build tree 不存在,未误报运行通过。
- `clang-format --dry-run --Werror`、`git diff --check`:通过。
- 未运行 Android Gradle、ADB、APK、设备测试或 Jest;没有 APK packaging 改动。
## 待用户 Android 验证
先只执行 T-FULL-01~03:256、1K、256→1K→256。确认 `trailDrawCount` 等于 effective count、视觉密度变化、持续运动,以及没有 Style reload / Field upload / MIX 改变后,再扩展到 4K/16K/64K/1M。
PowerShell 或 CMD:
```powershell
cd /mnt/sda1/MapLibreParticleLab/platform/android
./gradlew :MapLibreAndroidTestApp:assembleOpenglDebug -Pandroid.injected.build.abi=x86_64 --console=plain
adb -s 192.168.1.146 install -r .\MapLibreAndroidTestApp\build\intermediates\apk\opengl\debug\MapLibreAndroidTestApp-opengl-debug.apk
adb -s 192.168.1.146 logcat -c
adb -s 192.168.1.146 shell am start -n org.maplibre.android.testapp/.activity.particle.ParticleCoreLayerValidationActivity
adb -s 192.168.1.146 logcat -v time | Select-String -Pattern 'ParticleGPU|PARTICLE_COUNT|STATE|DRAW|trailDrawCount|effectiveParticleCount|stateGrid|fullParticleDraw|STYLE|FIELD|MIX'
```
APK:`./MapLibreAndroidTestApp/build/intermediates/apk/opengl/debug/MapLibreAndroidTestApp-opengl-debug.apk`。