fix: skip destroyed struct and stale render element in 2D render pass(2D 渲染跳过已销毁 struct 与失效 render element,修复 GList 虚拟滚动崩溃) - #2341
Open
xiaosong1985 wants to merge 1 commit into
Conversation
…(2D 渲染跳过已销毁 struct 与失效 render element,修复 GList 虚拟滚动频繁销毁/重建子节点时残留缓存引发的多处空指针崩溃) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
打开带 fairygui
GList滚动组件的界面、或虚拟列表频繁滚动/回收/销毁重建 item 时,2D 渲染路径出现多处空指针崩溃,例如:Cannot read properties of null (reading 'globalAlpha' / 'globalRenderData')atWebRender2DPass.cullAndSortCannot read properties of undefined (reading '_handleInterData')atWebRender2DPass.fowardRenderCannot read properties of null (reading 'clipInfo' / '_passes' / 'getClipInfo')at 渲染元素_compileShader/_render根因
虚拟滚动在极端 churn 下会频繁 移除+销毁子节点 / 回收 render element。被销毁的
WebRenderStruct2D及被回收的 render element 仍残留在所属 pass 的_structs/_renderElements缓存中;当该 pass 处于「非重绘快路径」时复用这些脏缓存,遍历/绘制到已失效对象 → 读到 null 字段崩溃。核心是结构/元素被销毁回收后,pass 缓存未被正确失效。修复
根因层(
WebRenderStruct2D):destroyed标记,destroy()置位;removeChild()在摘除前捕获子节点真实所在的 pass(带 cacheAs/mask 的父,其子渲染在父的 subpass,而非父自身 pass)并标记其repaint,让缓存重建、不残留对被移除子 struct 的引用。Pass 层(
WebRender2DPass):cullAndSort入口跳过已销毁 struct(原始globalAlpha崩溃点兜底);fowardRendermask 分支:subStruct 未就绪/已失效时本帧跳过合成,并保持repaint下帧重试;fowardRender非重绘分支:发现_structs缓存含已销毁 struct 时,本帧不绘制脏的_renderElements并强制下帧重建。渲染元素兜底层(
WebGLRenderElement2D/WebGLPrimitiveRenderElement2D):_prepare/_render跳过未就绪/已回收的元素(subShader/owner/_curCacheEntry为空),避免绘制到失效元素崩溃。验证
在基于 3.4 引擎的工程中用同事提供的必现压力用例复现并验证:1000 项虚拟滚动 GList,每帧疯狂滚动 +
itemRenderer里销毁重建子节点 + 反复切cacheAs/mask,并每帧递归校验渲染 struct 树父子一致性。经独立代码审查复核:
removeChild取 pass 时机正确、destroyed免复位假设成立(createRenderStruct2D无对象池)、元素级守卫不会误伤正常元素、stale提前 return 跳过uploadBuffer无副作用。本 PR 仅含共享层 + WebGL 驱动改动,不涉及子模块;WebGPU 驱动的同类元素级守卫将另行补充。
🤖 Generated with Claude Code