[显存/性能] SpriteRenderer 缺少显存资源释放:WebGL2 纹理、缓冲与程序持续泄漏 #9
Labels
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Blocks
#7 [Code Review] 整体代码质量、架构缺陷与技术债务全景审查报告
troytt/diablo2-web
Reference: troytt/diablo2-web#9
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
模块位置
src/render/renderer.ts,src/scene/act-scene.ts问题背景与现象
SpriteRenderer在初始化时分配了 Program、VertexShader、FragmentShader、VAO、VBO 以及白底/默认图集纹理。addAtlas每次加载关卡切片和角色动画时均调用gl.createTexture()创建 2048×2048 的 GPU 纹理。gl.deleteTexture、gl.deleteProgram、gl.deleteBuffer或gl.deleteVertexArray。SpriteRenderer甚至未对外暴露destroy()或dispose()方法。造成的影响
WebGL: CONTEXT_LOST_WEBGL崩溃。解决建议
SpriteRenderer中增加dispose()方法,显式清理 Program, Shaders, VAO, VBO 及所有托管纹理;deleteAtlas(handle: AtlasHandle)方法,支持按需释放指定 GPU 纹理对象;webglcontextlost/webglcontextrestored)以提供友好的降级提示与恢复逻辑。修复方案与验证报告
该问题已在 Commit
a80ee2c中彻底修复并推送至main分支。一、问题根因与修复实施
着色器驱动层泄漏消除(
src/render/renderer.ts):createProgram内部,Shader 链接完成后立即执行gl.detachShader和gl.deleteShader;gl.deleteProgram,彻底杜绝驱动层底层 Shader 对象的残留堆积。全量显存纹理追踪与按需释放(
src/render/renderer.ts):SpriteRenderer新增allocatedTextures = new Set<WebGLTexture>(),对构造函数初始分配以及addAtlas动态上传的所有 GPU 纹理进行统一追踪;deleteAtlas(handle: AtlasHandle): boolean方法:batchAtlas),先自动调用flush()提交已有顶点,并安全回退到默认纹理,避免悬挂采样或渲染崩溃。显式销毁生命周期(
src/render/renderer.ts):dispose()方法与isDisposed只读状态标志;gl.deleteBuffer)、VAO(gl.deleteVertexArray)以及 Shader Program(gl.deleteProgram);gl.isContextLost()状态防护,在 WebGL 上下文已丢失时不调用非法的 GL 删除指令;begin/setAtlas/addAtlas会立即拦截并抛出RendererError。WebGL Context Lost 保护与自动恢复(
src/render/renderer.ts):SpriteRenderer构造函数接收RendererOptions(onContextLost/onContextRestored);webglcontextlost事件并强制触发event.preventDefault()(遵循 WebGL 规范,只有 preventDefault 浏览器才会允许后续触发 context restored 恢复);业务场景生命周期与关卡切换集成:
src/scene/map-scene.ts/src/scene/net-scene.ts/src/walk.ts:模块级维护activeRenderer,在切换关卡、重新选择地图或拖入新 MPQ 时,先调用activeRenderer?.dispose();并在beforeunload时清理运行循环与显存;src/scene/act-scene.ts:在卸载前对runtime.pages中的所有 Atlas 以及角色 Handle 执行deleteAtlas,随后彻底dispose()。二、工程验证与自动化测试
生命周期自动化测试套件(
scripts/verify-renderer-lifecycle.ts):npm run verify:renderer命令;生产构建与类型检查: