Repository navigation
Conversation
|
Good stuff! The helper-level guard looks appropriate for #3652. Would you be interested in going a little further to clean up failed program links before retrying? ShaderProgram.link() currently clears the program handle without deleting the failed WebGL program or resetting its recorded shader attachment handles. The next retry creates another program and tries to detach those old shaders from it. I reproduced I’ve been looking at this area recently, and that cleanup is implemented in b4516233, part of an unmerged draft of mine. It could serve as a starting point if useful. |
A failed link cleared the program handle without deleting the program or resetting the recorded shader attachment handles. The shader cache keeps the failed program, so the next build creates a new program and detaches the old shaders from it, which raises INVALID_OPERATION. link now deletes the failed program, which detaches its shaders, and clears the attachment handles so a retry starts clean. Co-authored-by: Paul Elliott <paul@vizworkshop.com>
|
I ported the link-failure cleanup from b451623 into this PR, with you as co-author. link() now deletes the failed program and resets the vertex and fragment shader handles. I added a mocked-GL test that fails without the cleanup, because without it the retry detaches the old shaders from the new program. |
Context
Fixes #3652.
vtkOpenGLHelper.setOpenGLRenderWindownow restores an emptyvtkShaderProgramwhen a mapper has cleared the program, so a failed volume shader no longer crashes the next render pass.When a volume shader fails to compile or bind,
vtkOpenGLVolumeMapper.updateShaderscallscellBO.setProgram(null)and skips the draw. On the next pass,volumePasscallsmodel.tris.setOpenGLRenderWindow(...), which dereferences the null program:Results
Before: after a shader failure, the next render pass throws and the viewport stays blank.
After: the empty program has handle 0, so the
cellBO.getProgram()?.getHandle() === 0check ingetNeedToRebuildShaderstriggers a rebuild on the next pass. If the shader compiles, the cached program replaces the empty one. If it fails again, the mapper skips the draw as before, without the exception. A program that was not cleared is kept.I put the guard in the helper, as the issue suggests. A null check (
model.program?.setContext) would leave the program null, and sinceundefined === 0is false, the mapper would never rebuild. Setting an empty program at the two clear sites in VolumeMapper would fix only that mapper. The helper guard also covers the image mappers andHelper.updateShaders, which can store a null program after a failed compile.The empty program does not go into
ShaderCache.shaderProgramsand gets no GL handle (cleanup()does nothing when the handle is 0), so cache bookkeeping does not change.Changes
Sources/Rendering/OpenGL/Helper/index.js:setOpenGLRenderWindowcreates an emptyvtkShaderProgramwhenmodel.programis null, before it callssetContext. No API change.Sources/Rendering/OpenGL/Helper/test/testNullProgramRecovery.js: new regression test. One case replays the clear-then-next-pass sequence and asserts no throw, and that the empty program has handle 0, is not compiled and has the context. The other asserts that an existing program is not replaced.Out of scope:
Helper.updateShaderscan still use a null program in the same frame after a failed compile. That is a separate crash path for the other mappers, and the issue's notes exclude it.PR Checklist