Skip to content

Refactor API status handling and add occlusion culling - #95

Draft
ZhuRuoLing wants to merge 6 commits into
Anvil-Dev:dev/26.1from
ZhuRuoLing:feat/occusion_culling
Draft

Refactor API status handling and add occlusion culling#95
ZhuRuoLing wants to merge 6 commits into
Anvil-Dev:dev/26.1from
ZhuRuoLing:feat/occusion_culling

Conversation

@ZhuRuoLing

Copy link
Copy Markdown
Contributor

Summary

This PR lays the first-stage foundation for occlusion culling in the rendering module and clarifies the visibility of selected internal APIs. It introduces the culler abstraction, GPU Query resources and draw path, and an OpenGL samples-query wrapper. The selectable Hi-Z and Query culling backends will be integrated in follow-up work.

Changes

  • Added OcclusionCuller, OcclusionKey, and OcclusionMethod to provide a common abstraction for rendering-feature submission, visibility decisions, and backend selection.
  • Added the occlusion-query render pipeline and its vertex and fragment shaders. Query geometry is rendered as a unit cube transformed to the feature AABB through FullTransformsUbo.
  • Extended the GPU device interface and the OpenGL implementation with samples-query creation and result retrieval, including the GlSamplesQuery lifecycle wrapper.
  • Added reusable GPU resource and ring-buffer foundations, with dedicated pools for Query objects and Query draw buffers to reduce allocation pressure across consecutive frames.
  • Added Query frame-state management: the current frame submits and executes queries, while the following frame reads their results to decide whether a feature should be drawn.
  • Changed compute-pass debug-group messages to lazy Supplier<String> values, avoiding unnecessary debug-text construction.
  • Updated ApiStatus.Internal annotations by removing them from mixin classes and explicitly marking rendering and sync classes, records, and extension interfaces that are internal implementations.

Impact and Compatibility

  • The occlusion-culling types currently provide the underlying infrastructure; runtime backend selection and the complete feature-culling flow are not wired in yet.
  • ALRComputePass.pushDebugGroup and its backend implementation now accept Supplier<String> instead of String; direct implementations and callers of this internal API must be updated accordingly.
  • The annotation changes clarify internal API boundaries and do not alter public feature behavior.

TODO

  • Add a Hierarchical Z based culling backend.
  • Add a Samples Query based culling backend.
  • Integrate occlusion culling with vanilla SubmitNodeStorage

@ZhuRuoLing
ZhuRuoLing marked this pull request as draft August 7, 2026 21:58
@Gugle2308

Copy link
Copy Markdown

🌿 Roseau API Breaking Change Report

Module Status Breaking Changes
codec ✅ Compatible 0
collision ✅ Compatible 0
config ✅ Compatible 0
integration ✅ Compatible 0
moveable-entity-block ✅ Compatible 0
network ✅ Compatible 0
rendering 🔴 BC detected 5
space-select ✅ Compatible 0
font ✅ Compatible 0
util ✅ Compatible 0
explosion ✅ Compatible 0
rpc ✅ Compatible 0
multiblock ✅ Compatible 0
recipe ✅ Compatible 0
registrum ✅ Compatible 0
sync ✅ Compatible 0
wheel ✅ Compatible 0
main ✅ Compatible 0

🔴 rendering — 5 breaking change(s)

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:24

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.popDebugGroup(java.lang.String)
EXECUTABLE_REMOVED
✗ binary-breaking
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:20

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.pushDebugGroup(java.lang.String)
EXECUTABLE_REMOVED
✗ binary-breaking
✗ source-breaking

Full CSVs: see the Artifacts section of this workflow run.

@Gugle2308

Copy link
Copy Markdown

⚠️ Dangerous command requires approval:

cd /opt/data/workspace/AnvilLib && grep -rn "debugLabels\|pushDebugGroup" module.rendering/src/main/java/dev/anvilcraft/lib/v2/rendering/mixins/blaze3d/gl/GlDebugLabelMixin.java | head; echo "===GlDeb...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown

⏱️ Rate limited. Waiting 2.9s (attempt 2/3)...

@Gugle2308

Copy link
Copy Markdown

⏱️ Rate limited. Waiting 4.9s (attempt 3/3)...

@Gugle2308

Copy link
Copy Markdown

❌ Rate limited after 3 retries — Concurrency limit exceeded for user, please retry later

@Gugle2308

Copy link
Copy Markdown

API call failed after 3 retries: Concurrency limit exceeded for user, please retry later

@Gugle2308

Copy link
Copy Markdown

分析完成。以下是审查意见。

代码审查摘要 — PR #95

操作: synchronize
范围: 75 个文件 (70 Java, 29 新增, 0 删除) / 3249 行 diff
模块: module.rendering (主要) + module.sync (仅注解规范化) + module.test
分支: feat/occusion_culling → dev/26.1

🔴 关键(合并前需修复)

  • GlSamplesQuery.end()GL46.glEndQuery(id) 传参错误query/gl/GlSamplesQuery.java:34
    LWJGL 的 glEndQuery(int target) 接收的是 target 枚举GL_ANY_SAMPLES_PASSED),不是 query id。当前把 id 当 target 传入 → 每次 GL_INVALID_ENUM,query 永不结束;后续 glBeginQuery 会因同 target 已有活跃 query 而 GL_INVALID_OPERATION所有查询全部失效。更严重的是 getValue()GL_QUERY_RESULT 同步读取一个永不结束的 query 会永久阻塞渲染线程——一旦接入渲染管线就会整帧卡死。修复:GL46.glEndQuery(GL46.GL_ANY_SAMPLES_PASSED)

  • GlSamplesQuery.getValue() — 4 字节分配 + 8 字节越界读query/gl/GlSamplesQuery.java:52-55
    stack.nmalloc(4) 只分配 4 字节(GL_ANY_SAMPLES_PASSED 结果是 GLuint),却用 MemoryAccess.getLong(buffer)Unsafe.getLong)读 8 字节——高 32 位读到的是栈上残留垃圾。结果不确定:query 为 0(被遮挡)时若垃圾位非零,shouldDraw 会误判为可见(浪费填充率);这是 OOB 读,属于未定义行为。修复:用 MemoryAccess.getInt 读 4 字节(或 nmalloc(8) + glGetQueryObjectui64v)。

这两处意味着 PR 声称已完成的 "[x] Samples Query backend" 实际不可用——虽然当前未接线不会立即崩溃,但接入即挂。建议合并前修复(都是两行改动)。

⚠️ 警告

  • ConvertDepthParamsUbo / IntSizeUbo — 宽高顺序与 GLSL 声明相反
    DEFINITION 顺序是 getHeight, getWidth,而对应 GLSL(depth_convert.csh 及 javadoc)声明为 uWidth; uHeight;BufferObjectLayoutDefinition.writeInto 按条目顺序写入,第一个 4 字节 = Height 会落到 uWidth。Hi-Z 接入且深度纹理非正方形时边界检查会错。统一 getter 顺序或 GLSL 顺序其一即可。

  • fetchResults()GL_QUERY_RESULT 同步读取 → 每帧全管线停顿
    FrameState.fetchResults() 对每个 key 做一次阻塞读,等于每帧强制 GPU 完成全部已提交工作——对以性能为目的的遮挡剔除是自毁。建议改 GL_QUERY_RESULT_AVAILABLE 轮询或延迟 2+ 帧读结果。另外注意:beginFrame() 中先 close()(把 query 归还池)再读新 previous frame 的结果,当前安全完全依赖 GL_QUERY_RESULT 的阻塞语义——若改成非阻塞读,归还顺序会变成悬垂复用风险,需一并调整。

  • 首帧/新 key 全部判不可见 → 闪烁风险
    GpuQueryOcclusionCuller.shouldDraw()previousFrameState == null 时返回 false,新出现的 key 默认 0 也不画。culler 创建后第一帧全屏消失、新进入视野的物体延迟 1-2 帧才出现。惯例是"未知即画"(保守)避免 pop-in。

  • OcclusionMethod.GPU_QUERY 无能力检查 + 硬转 (ALRGpuDeviceExtension) device
    isSupported() 无条件返回 true,createInstance 直接强转——若 device mixin 未生效或 RenderSystem.getDevice() 为 null,直接 CCE/NPE。建议 instanceof 守卫。ALRHICapabilities.getInstance() 的强转同理(ALRComputeCapabilities.init()GL.getCapabilities() 改为依赖 mixin,健壮性回退——时机本身安全,BloomPostEffect 在同一注入点已读 getDevice())。

  • ALROptions.SPD_OPTION_WAVE_INTEROP_LDS 默认值 + define 映射反转
    getPropertyBoolean 未设置属性时默认 true,而 define 映射是 ? 0 : 1(代码里自己都注释了 "weird reverted")→ 默认走 wave intrinsics 路径,shader #extension GL_KHR_shader_subgroup_quad : require + image2DArray[13](超出 GL 最低保证的 8 个 image unit)。FFX_SPD pipeline 已在 ALRComputePipelines 注册,每次资源重载都会编译——不支持的 GPU 上会持续刷编译错误(好在外层降级为 INVALID 不崩溃)。建议默认映射到兼容路径并修正命名语义。

  • 新增 compute shader 用 Vulkan 风格 layout(set = 0, binding = N)
    桌面 GLSL 无 set 限定符,严格驱动会编译报错(depth_convert.csh 还用了 #version 460)。现有降级路径能兜住,但建议在目标驱动栈上验证。

💡 建议

  • BufferObjectLayoutEntry.Builder.forSetter(...) — setter 存进 Builder 但 build() 从未使用(record 只有 type+getter),且全 diff 无调用者 → 死 API,接线或删除。
  • FrameState.keys HashSet(含 import)— 声明后从未使用,删掉。
  • HierarchicalZOcculusionCuller — 类名/文件名拼写 "Occulusion" 与包名 occlusion 不一致;空实现 stub 建议在 createInstance 显式返回 null 即可(现状已如此),后续实现时注意。
  • GlSamplesQuery.getValue() 异常消息 "GlTimerQuery is closed" — 从计时 query 类复制粘贴的残留。
  • SPDConstantBuffer 缺少 @ApiStatus.Internal,同批 Hi-Z UBO(ConvertDepthParamsUbo/IntSizeUbo)都有 — 注解边界不一致。
  • FrameState.runQueries// ChatGPT can make mistakes. Check important info. — 开发期注释,删除。
  • 每个 key 一个 createRenderPass,N 个 feature = N 个 pass;可在单个 pass 内连续 begin/draw/end 所有 query(buffer 已用 ring buffer 摊销,pass 是剩余的最大开销)。
  • ALROptimizations.occlusionCuller 静态懒加载无同步 — 目前仅渲染线程调用,安全;若将来多线程访问需 volatile/加锁。

🟢 看起来不错

  • 帧状态机设计正确:当前帧提交+执行、下一帧读结果;查询对象两帧后归还,配合阻塞读语义无复用竞态;池自动扩容处理 key 数增长。
  • 单位立方体 + FullTransformsUbo 方案很干净:288 字节顶点缓冲复用,每 key 只换 modelview;变换数学验证无误(translate(min) × scale(max-min) × viewRotation × -camPos)。
  • OCCLUSION_QUERY pipeline 配置正确:POSITION/QUADS、color WRITE_NONE、LEQUAL 深度测试且不写深度、6 个面全部 CCW 正面朝外配合 withCull(true)
  • Supplier<String> 懒调试组重构在整条链(ALRComputePass → Backend → device extension → GlDebugLabel)一致完成,顺带删掉了 popDebugGroup 未使用的参数。
  • ApiStatus.Internal 重新分配(从 mixin 类移除、加到真实内部实现/UBO/record)符合描述意图,sync 模块 8 个文件规范化一致。

📋 声称验证表

声称 状态 对应文件
OcclusionCuller/OcclusionKey/OcclusionMethod 抽象 optimization/occlusion/*.java
查询渲染管线 + 顶点/片元着色器 + FullTransformsUbo ALRPipelines.OCCLUSION_QUERY, occlusion_query.vsh/.fsh
GPU 设备接口 + OpenGL samples-query(GlSamplesQuery 生命周期) ⚠️ GlSamplesQuery 存在但含 2 个 🔴 bug
可复用 GPU 资源 + ring buffer 基础(Query 池 / Query 缓冲池) GpuReusableResource(RingBuffer), LoopResetPool, SimpleResetPool, QueryBufferPack(RingBuffer)
Query 帧状态管理(当前帧提交执行、下帧读结果) FrameState, GpuQueryOcclusionCuller
compute-pass debug-group 懒 Supplier ALRComputePass(+Backend), GlComputePassBackend, GlDeviceMixin
ApiStatus.Internal 注解调整 15 个 mixin 移除 + 内部实现类补注
[x] Samples Query backend ⚠️ 已实现但 glEndQuery/越界读使其实质不可用
[ ] Hi-Z backend ✅(按 TODO 未声称完成) 仅存 stub + depth_convert/ffx_spd shader + SPD pipeline 注册,未接线
[ ] 接入 vanilla SubmitNodeStorage ✅(未声称完成) 未实现,符合描述

结论: REQUEST_CHANGES — 基础设施和框架设计扎实,但 GlSamplesQuery 的两处错误(glEndQuery target 传参 + 4/8 字节越界读)会让已声称完成的 Samples Query 后端在接入时立即挂起渲染线程;修复后再合并。其余为 Hi-Z 接线前的潜在问题,建议顺手修正宽高顺序和默认 flag 映射。


由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown

💾 Self-improvement review: Skill 'rendering-gpu-pr-review' created.

@Gugle2308

Copy link
Copy Markdown

所有文件已审查完毕。汇总分析结果,输出审查意见:


代码审查摘要 — PR #95 (synchronize)

操作: synchronize
范围: 76 个文件(29 新增 / 47 修改 / 0 删除)/ 3358 行 diff
模块: module.rendering(occlusion culling 基础设施 + 注解整理)+ module.sync(纯注解规范化)

📋 声称验证表

声称 状态 对应文件
OcclusionCuller/Key/Method 抽象 optimization/occlusion/*
occlusion-query 管线 + 顶点/片元 shader ALRPipelines.OCCLUSION_QUERY, occlusion_query.{vsh,fsh}
GPU device 接口 + GL samples-query 扩展 ALRGpuDeviceExtension, GlDeviceMixin, GlSamplesQuery
GPU 资源池 / ring-buffer 基础 GpuReusableResourcePool, QueryInstancePool, DynamicUniformStorage
帧状态管理(本帧提交、下帧读结果) FrameState, GpuQueryOcclusionCuller
pushDebugGroup → Supplier<String> 惰性化 5 处调用/实现全部迁移,无残留 String 调用
ApiStatus.Internal 注解调整 mixin 类移除(12 个)、内部实现类添加(sync 7 + rendering 若干)
Samples Query 后端 GpuQueryOcclusionCuller(已实现)
Hi-Z 后端 ✅(骨架) HierarchicalZOcculusionCuller 空壳 + OcclusionMethod.HIERARCHICAL_Z.createInstance 返回 null
与 vanilla SubmitNodeStorage 集成 ✅(未接线) ALROptimizations.getOcclusionCuller() 无任何调用者

🔴 关键(接入即错的 latent bug,建议合并前修)

  • IntSizeUbo / ConvertDepthParamsUbo 宽高互换BufferObjectLayoutDefinition.writeInto 按 entries 顺序写入(已在本地 dev/26.1 克隆验证),但 IntSizeUbo.DEFINITIONgetHeightgetWidth,GLSL 声明却是 int uWidth; int uHeight;ConvertDepthParamsUbo 同理。结果:depth_convert.csh 的边界检查 idx.x >= uWidth || idx.y >= uHeight 拿到互换后的值,宽图时右/下半区域被错误填充 uPadValue=1(深度 1.0=最远),Hi-Z 深度数据损坏。当前 Hi-Z 未接线所以不触发,但 UBO 定义就是错的,接上即坏——建议把两个 UBO 的 entry 顺序改为 getWidth, getHeight
  • HierarchicalZOcculusionCuller.shouldDraw 返回 false(空壳) — 永不绘制。目前被 OcclusionMethod.HIERARCHICAL_Z.createInstance() → null 挡住,但任何人把该分支接通就会全屏消失。空壳至少应返回 true 或抛 UnsupportedOperationException,并加 @ApiStatus.Internal(或直接删除)。
  • OCCLUSION_QUERY pipeline withCull(true) — 相机位于 feature AABB 内部时(玩家走进大型结构/多方块建筑,很常见),单位立方体所有面都成背面被剔除 → 查询 0 samples → 下一帧 shouldDraw=false → 物体消失闪烁。遮挡查询的 box 应 cull(false):深度 LEQUAL 下背面样本无害(背面深度 ≥ 正面,正面通过则结果一致),而剔除背面则盒内相机场景必然误判。

⚠️ 警告

  • ffx_spd_downsample_pass.csh 是 Vulkan GLSL 混用 + 无条件注册layout (set = 0, binding = N) 是 Vulkan 语法(OpenGL 严格驱动直接编译报错);#extension GL_KHR_shader_subgroup_quad : require 使无 subgroup quad 的 GPU 编译失败;image2DArray rw_input_downsample_src_mips[13] 超出 GL 最低保证的 8 个 image unit。且该 pipeline 已在 ALRComputePipelines 注册(ALRComputeShaderManager 每次资源重载都会编译它),而 Hi-Z 未接线——为死代码付编译成本 + 兼容性风险双重问题。建议 Hi-Z 完成前不要注册。
  • ALRComputeCapabilities.init() 时机迁移的健壮性 — 从 ALRComputeShaderManager.apply(失败仅 log 降级)移到 MinecraftMixin.onCreateInstance(启动即崩路径)。ALRHICapabilities.getInstance() 硬转 (ALRGpuDeviceExtension) RenderSystem.getDevice(),mixin 未生效时 CCE。同注入点已有 ALRPostEffects.createPostEffects() 读 getDevice()(既有代码工作正常),大概率安全,但无回退。
  • OcclusionMethod.GPU_QUERY.isSupported() 无条件 true(假支持)createInstance(ALRGpuDeviceExtension) device 无 instanceof 守卫。由于 createInstance 优先走 Hi-Z 分支(恒 null)再落到 GPU_QUERY,任何 GPU 上都会创建 GPU_QUERY culler,isSupported 形同虚设。建议探测 device instanceof ALRGpuDeviceExtension
  • GL_QUERY_RESULT 同步阻塞读与池复用时序绑定GlSamplesQuery.getValue() 每帧对 N 个 query 逐个同步读(高负载下 GPU 落后即管线停顿,与遮挡剔除的性能目标相悖);更关键的是:FrameState.close() 释放 query 回池的安全性完全依赖阻塞读语义——当前时序(帧 N+1 读、帧 N+2 复用)恰好安全,但一旦改成 RESULT_AVAILABLE 非阻塞读,复用的 query id 可能仍在飞行中 → 悬垂复用。两者是一体的,请加注释锁定此依赖。
  • FFX_SPD_OPTION_WAVE_INTEROP_LDS define 反转 + 默认 trueALROptions.getPropertyBoolean 对未设置属性返回 true(默认走 wave interop 路径),配合反转映射 ? 0 : 1(注释 "weird inverted")和 shader 的 subgroup_quad : require,默认配置恰好导向兼容性最差的路径。建议默认改为纯 LDS 路径(define 1)。

💡 建议

  • MemoryAccesssun.misc.Unsafe 反射 — Java 21 模块系统下 theUnsafesetAccessible(true) 需要 jdk.unsupported 开放(launcher 的 --add-opens 不保证包含);GlSamplesQuery 只需 4 字节读,直接用 LWJGL MemoryUtil.memGetInt 更稳。
  • ALROptimizations.getOcclusionCuller()RenderSystem.getDevice() 可能在渲染线程外为 null → createInstance(null) 硬转 CCE,加 null 守卫。
  • QueryInstancePool(2) / GpuSampleQueryPool(16) 初始容量偏小 — 活跃 key 超过即触发 expand()(虽只建 CPU 侧对象,但 expand 后不缩容,峰值后池永久变大)。
  • BufferObjectLayoutEntry.Builder.forSetter 已加但 build() 未使用 — setter 字段被忽略,属半成品死代码。
  • BufferObject.createDynamicStorage@Deprecated(forRemoval) 且无调用方 — 可直接删除。

🟢 看起来不错

  • GlSamplesQuery GL 调用全部正确:glBeginQuery(GL_ANY_SAMPLES_PASSED, id) 双参 / glEndQuery(GL_ANY_SAMPLES_PASSED) 单参(target 而非 id)/ nmalloc(4) + getInt 宽度匹配(4 字节结果 4 字节读)。
  • FullTransformsUbo getter 顺序 ↔ GLSL 声明顺序一致;QueryInstance 矩阵链 translate(min)·scale(size) 验证正确(单位立方体 → inflate(0.1) 后的 AABB)。
  • 未知 key 首帧语义保守(results.getOrDefault(key, 1) → 默认画,previousFrameState == null 时画)✅ 符合遮挡剔除惯例。
  • 单 renderPass 内连续 begin/draw/end 所有 query(无 N-pass 开销)✅。
  • 资源池复用逻辑(LoopResetPool 循环扫描 + fail 兜底 expand)正确,无 NPE 路径。
  • ApiStatus.Internal 注解调整彻底且风格与 chore(annotations): 添加 ApiStatus.Internal 注解到内部接口和类 #93/refactor(common): 优化代码导入 #96 一致;FFX SPD shader 附 AMD 官方 license 头;BufferObject.write 增加 SSBO 误用 guard。
  • sync 模块 7 个文件均为纯注解规范化(@org.jetbrains... → import 后 @ApiStatus.Internal),无行为变更。

结论: COMMENT — 基础设施质量高(GL 传参、矩阵数学、池复用均正确),PR 明确未接线所以当前不会影响运行;但 3 个关键项(UBO 宽高互换、Hi-Z 空壳 shouldDraw=falsecull(true) 盒内误判)都是「接入即挂」的确定性 latent bug,建议合并前至少修复 UBO 顺序,其余项记录为集成 Hi-Z/SubmitNodeStorage 前的必改清单。


由 Hermes Agent 审查

@ZhuRuoLing
ZhuRuoLing force-pushed the feat/occusion_culling branch from 3c58b50 to 4cdf68c Compare August 13, 2026 22:34
@Gugle2308

Copy link
Copy Markdown

💾 Self-improvement review: Patched SKILL.md in skill 'rendering-gpu-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown

⚠️ Dangerous command requires approval:

unzip -l /tmp/nf26-sources.jar 2>/dev/null | head -5; echo "==="; python3 -c "
import zipfile
z = zipfile.ZipFile('/tmp/nf26-sources.jar')
names = [n for n in z.namelist() if 'DynamicUniformStorage' i...

Reason: script execution via -e/-c flag

Reply /approve to execute, /approve session to approve this pattern for the session, /approve always to approve permanently, or /deny to cancel.

@Gugle2308

Copy link
Copy Markdown

🌿 Roseau API Breaking Change Report

Module Status Breaking Changes
codec ✅ Compatible 0
collision ✅ Compatible 0
config ✅ Compatible 0
integration ✅ Compatible 0
moveable-entity-block ✅ Compatible 0
network ✅ Compatible 0
rendering 🔴 BC detected 6
space-select ✅ Compatible 0
font ✅ Compatible 0
util ✅ Compatible 0
explosion ✅ Compatible 0
rpc ✅ Compatible 0
multiblock ✅ Compatible 0
recipe ✅ Compatible 0
registrum ✅ Compatible 0
sync ✅ Compatible 0
wheel ✅ Compatible 0
main ✅ Compatible 0

🔴 rendering — 6 breaking change(s)

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:24

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.popDebugGroup(java.lang.String)
EXECUTABLE_REMOVED
✗ binary-breaking
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:20

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.pushDebugGroup(java.lang.String)
EXECUTABLE_REMOVED
✗ binary-breaking
✗ source-breaking

Full CSVs: see the Artifacts section of this workflow run.

@Gugle2308

Copy link
Copy Markdown

All verification complete. I have a full picture of the PR. Writing the review:

代码审查摘要 — PR #95

操作: synchronize
范围: 75 个文件(29 新增)/ 3297 行 diff
主题: 遮挡剔除第一阶段基础设施 + API 状态注解整理

🔴 关键(接入前必须修复)

  • IntSizeUbo.java / hiz/ConvertDepthParamsUbo.java — 宽高互换(确定性 bug)
    Java 侧 DEFINITION 的 entry 顺序是 getHeightgetWidth,而 BufferObjectLayoutDefinition.writeInto 严格按 entry 顺序写入(已用本地克隆 dev/26.1 分支核实),第一个 entry 落在 GLSL 第一个声明字段。两个 UBO 的 javadoc GLSL 均为 int uWidth; int uHeight; → 实际写入是 height→uWidth, width→uHeight。一旦 Hi-Z 接线,depth_convert.cshidx.x >= uWidth 判边界,互换后有效深度数据会落在错误区域、越界区反而被写入 pad 值 1.0。当前无调用方(latent),但这是接入即现的错误。修复:entry 顺序改为 getWidth, getHeight

  • ALRPipelines.OCCLUSION_QUERYwithCull(true) + 相机在 AABB 内部时查询恒为 0
    查询几何是包围盒立方体,开启背面剔除后,当相机位于 feature 的 AABB 内部(玩家站在被剔除建筑里是常态),6 个面全部为背面 → 0 样本通过 → shouldDraw 返回 false → 下一帧整个 feature 消失(pop-in)。遮挡查询 pass 的三角形数量(36 索引 × N)远小于剔除收益,建议 withCull(false),或至少加"相机在盒内强制绘制"守卫。

  • HierarchicalZOcculusionCuller.shouldDraw 恒返回 false
    占位桩的危险默认值:一旦 OcclusionMethod.HIERARCHICAL_Z.createInstance() 改为返回它(任务清单里 Hi-Z 是 next step),所有 feature 会被全部剔除。占位实现建议返回 true(保守画),与 Query 后端的语义保持一致。

⚠️ 警告

  • 硬转无 instanceof 守卫(latent CCE)OcclusionCuller.createInstanceALRHICapabilities.getInstance() 均直接 (ALRGpuDeviceExtension) RenderSystem.getDevice()。GpuDeviceMixin 未应用(mixin 冲突/插件禁用)→ CCE;早期调用时 getDevice() 可能为 null → NPE。且 OcclusionMethod.GPU_QUERY.isSupported() 无条件返回 true,是"假支持"探测——实际硬性前置只有 mixin 是否生效。建议 isSupported 里做 instanceof 检查或 try-catch。
  • ALRComputeCapabilities.init() 时机搬移引入 mixin 依赖 — 从资源重载(ALRComputeShaderManager)移到 MinecraftMixin 构造器 RETURN。与同注入点的 ALRPostEffects/CachedBlockEntityRenderingPipeline 一致,通常安全;但旧代码 GL.getCapabilities() 不依赖 mixin,新代码依赖注入接口 → mixin 失败从"重载时降级"变成"启动即崩"(AbstractMethodError/CCE)。可接受,但建议确认 mixin 应用的失败路径。
  • ComputeSupport.INSTANCE 现在可能为 nullmodule.testGuiTestScreen / AnvilLibTestClient 均直接 ComputeSupport.INSTANCE.xxx 无空检查 → 非 compute GPU 上测试直接 NPE(行为变更)。建议测试入口加空值守卫或改为可空延迟初始化。
  • QueryInstance.CreationContext 静态 vertexBuffer — static GpuBuffer 跨所有 culler/设备共享:设备重建(context loss)后悬垂;QueryInstance.close() 是空实现,GpuQueryOcclusionCuller 也没有 destroy/close 路径 → query 池、commandEncoder 永不释放。接线前需要生命周期钩子(如 OcclusionCuller.close() + 资源重载重建)。
  • ALROptions.SPD_OPTION_WAVE_INTEROP_LDS 命名反转 — 属性默认 true → define 0(LDS-only 兼容路径),效果与属性名相反(作者注释 "weird inverted")。且非默认路径启用 #extension GL_KHR_shader_subgroup_quad : require → 无 quad subgroup 的 GPU(GL < 4.6/旧硬件)编译失败;该 compute pipeline 已注册,每次资源重载都会编译并刷错误日志。建议反转映射或改名,并在 PR 描述中说明默认值语义。
  • 未接线状态的副作用ALROptimizations.getOcclusionCuller() 目前无任何调用者(AnvilLib 与 AnvilCraft 均 grep 不到),processFeatures 也无人调用 → query 从未 begin/end 时 fetchResults 读未使用 query(GL 结果实现定义,多数驱动返回 0)→ 全剔除。接线时必须同时接入 processFeatures 与 shouldDraw 的完整调用链,否则上述 latent 问题会全部同时爆发。

💡 建议

  • GlSamplesQuery.getValue() — 异常消息 "GlTimerQuery is closed" 是复制粘贴残留,应为 "GlSamplesQuery"。GL_QUERY_RESULT 阻塞读已通过"帧首读上一帧"缓解;若后续实测高负载帧停顿,可换 GL_QUERY_RESULT_AVAILABLE 轮询。
  • occlusion_query.fsh — pipeline 已 WRITE_NONE,fragColor 不会落屏,可用 discard 让意图更明确(可选)。
  • FrameState.runQueries — 单 RenderPass 内连续 begin/draw/end 全部 query,结构正确;getBuffer(6*6)(36 索引 = 6 面 QUADS)与 24 顶点 VB 匹配无误。
  • DynamicUniformStorage 512 容量 — MC 26.1 实现超限自动扩容(类内已有 resize 逻辑),无需担心。
  • BufferObject.createDynamicStorage16 — 经核实是修复:构造器第三参是 initialCapacity(非 usage),旧代码误传 USAGE_UNIFORM | USAGE_COPY_DST(=18)当容量;新代码显式 16 + SSBO 守卫 + @Deprecated(forRemoval) 一致。建议在 PR 描述中注明此修复。

🟢 看起来不错

  • GL query API 传参全部正确glBeginQuery(target, id) 双参、glEndQuery(GL_ANY_SAMPLES_PASSED) 只传 target(未把 id 当 target 传);nmalloc(4) 分配与 MemoryAccess.getInt 读取宽度一致(无越界读)。
  • 池复用时序安全 — 阻塞读发生在 release 之前、query 两帧后才归还池,无悬垂复用;FrameState.close()beginFrame 的帧间交接(S(n-2) 归还 → S(n-1) 读取 → S(n) 新建)自洽。
  • 未知 key 语义保守shouldDraw 对无结果 key 默认 1、首帧 previousFrameState 为 null 时返回 true,符合"未知即画"惯例,无首帧全屏消失问题。
  • FullTransformsUbo 字段顺序正确 — getter 顺序(ProjMat → ModelViewMat)与 occlusion_query.vsh 的 GLSL 声明一致(对比之下更凸显另两个 UBO 的互换)。
  • OCCLUSION_QUERY 管线配置正确WRITE_NONE + depth write false + LESS_THAN_OR_EQUAL,查询 pass 不污染主颜色/深度目标,且在地形之后执行,遮挡语义正确。
  • Supplier<String> debug group 重构完整 — 接口(ALRGpuDeviceExtension/ALRGpuDeviceBackendExtension)、后端(GlDeviceMixin/GlComputePassBackend)、调用点(ALRComputePass)全链路一致,popDebugGroup 去参干净。
  • ApiStatus.Internal 注解清理与描述一致 — mixin 类(MinecraftMixin/GuiRendererMixin/GpuDeviceMixin 等 ~12 个)移除注解,内部实现类/扩展接口/sync 模块 ~20 处补标,sync 模块 8 个文件为纯注解变更。

📋 声称验证表

声称 状态 对应文件
OcclusionCuller / OcclusionKey / OcclusionMethod 抽象 3 个新文件
occlusion-query 管线 + 顶点/片元着色器 ALRPipelines.OCCLUSION_QUERY + vsh/fsh
GPU 设备接口扩展 + GlSamplesQuery ALRGpuDeviceExtension(+Backend)、GlDeviceMixin、GpuDeviceMixin、ALRHICapabilities
GPU 资源/ring-buffer 池基础 GpuReusableResource(Pool)、LoopResetPool、SimpleResetPool
Query 帧状态管理(本帧提交、次帧读结果) FrameState、GpuQueryOcclusionCuller、QueryInstance
pushDebugGroup 改 Supplier ALRComputePass 全链路
ApiStatus.Internal 注解调整 渲染 + sync 模块
Samples Query 后端 ⚠️ 已实现但未接线 GpuQueryOcclusionCuller;ALROptimizations.getOcclusionCuller() 无调用者
Hi-Z 后端 ⚠️ 仅骨架 HierarchicalZOcculusionCuller 空实现 + ffx_spd/depth_convert + UBOs;createInstance 返回 null
集成 vanilla SubmitNodeStorage ❌ TODO 无对应代码

🧪 测试建议

被测目标 推荐测试场景 优先级
FrameState.runQueries/fetchResults 连续多帧 key 增删:池无重复 acquire、结果延迟一帧生效、释放后复用安全 🔴
UBO 布局(接入后) IntSizeUbo/ConvertDepthParamsUbo 写入字节与 GLSL 声明逐字段对照 🔴
GpuQueryOcclusionCuller.shouldDraw 相机在 AABB 内部 / 包围盒部分可见 / 完全被地形遮挡三场景 🟡
GlSamplesQuery.getValue 查询未 begin/end 时读取、release 后结果重置、close 后抛异常 🟡

结论: REQUEST_CHANGES — 基础设施质量整体很高(GL 调用、池时序、帧状态设计都正确),但三个 🔴 均为确定性缺陷:两个 UBO 宽高互换是接入即现的错误、withCull(true) 在相机入盒场景会错误剔除、Hi-Z 占位桩默认返回 false 是隐患。三者修复成本都极低(各一行级别),建议修复后再合入,避免错误语义沉淀到后续接线 PR。ALROptimizations 的接线入口建议在本 PR 内补一个最小调用链(哪怕只在 debug 模式),让 latent 问题能在真实帧循环中提前暴露。


由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown

💾 Self-improvement review: Patched SKILL.md in skill 'rendering-gpu-pr-review' (1 replacement).

@Gugle2308

Copy link
Copy Markdown

🌿 Roseau API Breaking Change Report

Module Status Breaking Changes
codec ✅ Compatible 0
collision ✅ Compatible 0
config ✅ Compatible 0
integration ✅ Compatible 0
moveable-entity-block ✅ Compatible 0
network ✅ Compatible 0
rendering 🔴 BC detected 9
space-select ✅ Compatible 0
font ✅ Compatible 0
util ✅ Compatible 0
explosion ✅ Compatible 0
rpc ✅ Compatible 0
multiblock ✅ Compatible 0
recipe ✅ Compatible 0
registrum ✅ Compatible 0
sync ✅ Compatible 0
wheel ✅ Compatible 0
main ✅ Compatible 0

🔴 rendering — 9 breaking change(s)

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/ALRGpuDeviceExtension.java

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.ALRGpuDeviceExtension
TYPE_NEW_ABSTRACT_METHOD
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:66

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.bind(int,dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ComputeBindingLayout<T>,T)
METHOD_RETURN_TYPE_ERASURE_CHANGED
✗ binary-breaking
✓ source-compatible

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:66

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.bind(int,dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.bindings.ComputeBindingLayout<T>,T)
METHOD_RETURN_TYPE_CHANGED_INCOMPATIBLE
✓ binary-compatible
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:24

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.popDebugGroup(java.lang.String)
EXECUTABLE_REMOVED
✗ binary-breaking
✗ source-breaking

dev/anvilcraft/lib/v2/rendering/extension/blaze3d/compute/pipeline/ALRComputePass.java:20

dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass
dev.anvilcraft.lib.v2.rendering.extension.blaze3d.compute.pipeline.ALRComputePass.pushDebugGroup(java.lang.String)
EXECUTABLE_REMOVED
✗ binary-breaking
✗ source-breaking

Full CSVs: see the Artifacts section of this workflow run.

@Gugle2308

Copy link
Copy Markdown

审查完成,所有关键路径已交叉验证(本地克隆 AnvilLib@dev/26.1、MC 26.1 反编译产物、shader、GL 常量值)。以下是审查意见:

代码审查摘要 — PR #95

操作: synchronize
范围: 83 个文件(78 Java,35 新增,0 删除)/ 3932 行 diff

🔴 关键(确定性代码缺陷,接入即触发)

  • ALRComputePass.bindAll — 首轮调用必崩ALRComputePass.java
    新代码 bindingPoint += this.bind(bindingPoint, binding, elements.get(bindingPoint - 1));bindingPoint 初始为 0 → 第一轮即 elements.get(-1)IndexOutOfBoundsException。旧代码是 bind(bindingPoint++, ..., elements.get(bindingPoint - 1))(先自增后取,等价 get(0)),语义在改签名时被破坏。应改为 elements.get(bindingPoint)。当前无调用者(已确认),但任何第一次 bindAll 调用都会崩。

  • QueryInstance.prepareMesh — x+ 面绕序反向QueryInstance.java
    x+ 面顶点 (1,0,0)→(1,0,1)→(1,1,1)→(1,1,0) 的叉积法线为 (-1,0,0),与 outward +x 相反(其余 5 面均正确)。配合 OCCLUSION_QUERYwithCull(true),从 +x 方向观察时正面被剔除,仅剩 4 个掠射面 → 大 AABB 正面直视时 samples 可能为 0 → 视野内的物体会被误剔除。修复:x+ 面改为 (1,y0,z1),(1,y0,z0),(1,y1,z0),(1,y1,z1) 或等价绕序。

  • ALRPipelines.OCCLUSION_QUERY 仍是 withCull(true) — 相机位于 feature AABB 内部(玩家走进大型结构)时立方体所有面均背面剔除 → 0 samples → shouldDraw=false → 物体消失/闪烁。遮挡查询盒应 cull(false)(深度 LEQUAL 下背面样本无害)。上轮已提出,本次未见修改。

  • IntSizeUbo — 宽高互换未修复IntSizeUbo.java
    DEFINITION 顺序 getHeight → getWidth,与自身 javadoc 的 GLSL 声明 uWidth; uHeight; 相反。同轮次 ConvertDepthParamsUbo 已改为 getWidth → getHeight ✅(与 depth_convert.csh 一致),唯独此类仍是反的。当前无调用者(dead code),但一旦用于任何尺寸参数即互换。

⚠️ 警告(latent,接入 Hi-Z / SubmitNodeStorage 时必踩)

  • FFX_SPD_DOWNSAMPLE_PASS 绑定布局与 shader 不一致
    shader 声明 binding=2rw_internal_global_atomic(std430 coherent buffer),但 pipeline builder 只注册了 cbFSR1@0、texture@1、mid_mip@2、mips@3——缺少原子计数器绑定bindAll 连续分配时 mid_mip/mips 整体错位 1 个 binding 点,且原子计数器永远不会被绑定(dispatch 时读未绑定 SSBO = UB)。另外 ImageArrayBinding 未覆写 applyOrdered(默认返回 1,13 个 image 只推进 1),且 Preconditions.checkElementIndex(size, resource.size(), ...) 参数颠倒——合法输入(resource.size()==size)抛异常,非法输入不抛。三者都是接入时才爆。

  • GlSamplesQuery.getValue() 每 key 每帧一次 GL_QUERY_RESULT 阻塞读 — 对以性能为目的的剔除是自伤模式(N 个 key = N 次管线停顿)。一帧延迟部分缓解,但注意:query 池的 release→reacquire 复用安全完全依赖本次阻塞读语义(F1 查询结果在 F2 读、F3 才归还复用,时序自洽 ✅)——将来改非阻塞读时必须同步调整归还顺序,否则变成悬垂复用。

  • MemoryAccess 仍用 sun.misc.Unsafe 反射Unsafe.theUnsafe + setAccessible(true),123 行只为读 4 字节)——GlSamplesQuery 只需 4 字节读,MemoryUtil.memGetInt 足够;Java 21 模块系统下 jdk.unsupported 未 open 时类加载即崩。本次 4 字节读本身宽度匹配正确(nmalloc(4) + getInt ✅),问题在机制本身。

  • ALROptimizations.create() 时序 + 空守卫
    MinecraftMixin.onCreateInstanceALROptimizations.create() 先于 ALRComputeCapabilities.init() 执行 → 启动时 HIERARCHICAL_Z.isSupported() 恒为 false → 后端选择永远是 GPU_QUERY,与 createInstance 内 HiZ 优先的意图矛盾;② getOcclusionCuller()RenderSystem.getDevice() 无 null 守卫(渲染线程外调用 → 硬转链 NPE);③ 创建的 culler 全库无人消费,静态持有 16 个 GL query + DynamicUniformStorage(512)(HiZ 路径则是 13 张纹理 + 3 个 buffer),纯浪费。

  • OcclusionCuller.createInstance 优先返回 HiZ 空壳 — compute 可用时选中 HierarchicalZOcclusionCuller(submit/process 均 no-op,shouldDraw=true ✅ 保守),实现完整的 Query 后端反而不被选中;该 stub 构造函数在未实现时已分配全部 GPU 资源,且无 close()/资源释放路径deleteTextures 只关纹理,spdParamsBuffer/convertParamsBuffer/spdGlobalAtomicCounterBuffer 三个 GpuBuffer 泄漏)。

  • ffx_spd_downsample_pass.csh 兼容性 — ① 桌面 GLSL 450 使用 Vulkan 风格 layout(set=0, binding=N):严格驱动编译报错,宽松驱动忽略(需在目标驱动栈验证);② 默认配置(SPD_OPTION_WAVE_INTEROP_LDS=true → define 0,注释已承认 "weird inverted")走 #extension GL_KHR_shader_subgroup_quad : require 路径——无 subgroup quad 的 GPU 编译失败;③ rw_input_downsample_src_mips[13] 超过 GL 最低保证的 8 个 image unit;④ 该 pipeline 已注册(资源重载即编译)但从未 dispatch,编译失败会持续刷日志。

  • MipLayer.getDefinition() 返回 null — 违反 BufferObject 基类契约,任何 size()/write() 调用即 NPE;作为纯数据 holder 不应继承 BufferObject

  • BufferObjectLayoutEntry.Builder.forSetter 是死 API — setter 字段从未传给 build()(record 无 setter 组件)。

  • GpuReusableResourcePool.fail(false) 返回 pool[0] 不检查可用性 — 双 acquire 悬垂复用(SimpleResetPool.acquire(false) 同路径;当前无调用者,dormant)。

  • QueryInstance.CreationContext 静态 vertexBuffer — record 内 static 可变字段,永不释放;设备重建/资源重载后悬垂。

💡 建议

  • GlDeviceMixin 用魔数 usage & 16 判 cubemap——已核实 MC 26.1 USAGE_CUBEMAP_COMPATIBLE == 16 ✅ 功能正确,但建议改用 GpuTexture.USAGE_CUBEMAP_COMPATIBLE 常量。
  • tonemappers.glsl(159 行)新增但 diff 与基线中均无任何引用——dead include。
  • sync 模块多处重复 import org.jetbrains.annotations.ApiStatus(如 LazySyncBytecodeInjector)。
  • 5 个文件缺末尾换行:MemoryAccess.javaLoopResetPool.javaSimpleResetPool.javadepth_convert.cshExtendedTextureFormat.java
  • 帧内 fetchResults 可先轮询 GL_QUERY_RESULT_AVAILABLE 减少无条件停顿。

🟢 看起来不错

  • glBeginQuery(target,id) / glEndQuery(target) / glGetQueryObjectuiv 传参全部正确(end 用 target 枚举 ✅),结果读取宽度匹配 ✅。
  • FullTransformsUbo(ProjMat→ModelViewMat)、ConvertDepthParamsUbo(width→height→padValue)、SPDConstantBuffer(mips→numWorkGroups→workGroupOffset→invInputSize)的 DEFINITION 顺序与各自 GLSL 声明逐字段一致writeInto 按 entries 顺序写入已验证)✅。
  • 未知 key 首帧语义保守:shouldDraw 首帧返回 true、getOrDefault(key, 1) 默认画 ✅;HiZ stub shouldDraw=true ✅(上轮意见已采纳)。
  • 查询 pass 单 RenderPass 批量提交全部 query(非每 feature 一个 pass)✅;debug group 惰性 Supplier 改造完整(接口/GL 后端/mixin 全链路一致)✅。
  • FrameState 双缓冲时序自洽:F1 提交 → F2 读结果 → F3 归还复用,阻塞读语义下池复用安全。
  • @ApiStatus.Internal 从 15 个 mixin 类移除、标注内部实现类,与 PR 描述一致 ✅。

📋 声称验证表

声称 状态 对应文件
OcclusionCuller/Key/Method 抽象 optimization/occlusion/*
查询管线 + 顶点/片元 shader + FullTransformsUbo ✅(含 🔴 绕序/cull 问题) ALRPipelines, occlusion_query.*, FullTransformsUbo
GPU device 接口 + GL samples-query 封装 GlSamplesQuery, GpuQueryObject, GlDeviceMixin
资源池 + ring buffer 基础 ✅(含 ⚠️ fail(false) 隐患) GpuReusableResourcePool, LoopResetPool, SimpleResetPool
帧状态管理(本帧提交/次帧读取) FrameState, GpuQueryOcclusionCuller
compute debug-group 惰性 Supplier ALRComputePass, GlComputePassBackend
ApiStatus.Internal 注解调整 15 个 mixin 移除 + 内部类标注
Hi-Z 后端 ⚠️ 仅 stub(TODO 未勾选,自认) HierarchicalZOcclusionCuller
Samples Query 后端 ⚠️ 已实现但未接线 GpuQueryOcclusionCuller
接入 vanilla SubmitNodeStorage ❌ TODO 未勾选(自认)

🧪 测试建议

被测目标 推荐场景 优先级
ALRComputePass.bindAll 首次调用即 IOOBE(当前必现) 🔴
ImageArrayBinding.apply resource.size() == size> size 两分支(当前逻辑颠倒) 🔴
QueryInstance 立方体 从 +x/-x 各方向 + 相机在 AABB 内部观察(samples 是否 >0) 🔴
GpuSampleQueryPool 连续 3 帧 key 数 > 池容量,验证 expand 与 release 时序 🟡
ALROptimizations 启动顺序(create 先于 compute init)下的后端选择断言 🟡

结论: REQUEST_CHANGES — 基础设施方向正确、多数问题因未接线而处于 latent;但 bindAll 是对既有 API 的确定性回归、x+ 面绕序与 IntSizeUbo 宽高互换是确定的代码缺陷,建议合并前修复;其余 ⚠️ 项作为接入 Hi-Z/SubmitNodeStorage 时的必办清单保留在 PR 中跟踪。


由 Hermes Agent 审查

@Gugle2308

Copy link
Copy Markdown

💾 Self-improvement review: Patched SKILL.md in skill 'rendering-gpu-pr-review' (1 replacement).

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.

2 participants