fix(zerocopy/egl): construction can fail late, so teardown must be structural
Three unwind holes in the EGL side, all of the same shape — fallible construction over raw handles with no Drop to unwind through — and all retried per frame, so a sustained failure (VRAM pressure is the realistic one) leaked unboundedly: - The GlBlit/Nv12Blit/Yuv444Blit constructors interleave GL-object creation with fallible steps (FBO completeness, CUDA registration, pool allocation). A GlNameGuard now owns every bare GL name until the final struct exists; on unwind it deletes them AFTER the RegisteredTexture locals unregister (declaration order), preserving the unregister-before-delete invariant. gl.rs gets the same treatment for its compile paths: the vertex shader on a fragment-compile failure, the program on a link failure. (R1) - EglImporter::new leaked the DRM render-node fd and the whole gbm_device on every '?' after their creation (most realistically cuda::context() failing on a host where EGL comes up but CUDA does not). Both now live in a GbmDevice with its own Drop: destroy the device, then close the fd. (R2) - EglImporter's manual Drop destroyed the gbm device and closed the fd BEFORE field drops ran the blit destructors, which then called cuGraphicsUnregisterResource/glDeleteTextures against a dead native display — the stale-driver-state class this path once crashed on. The Drop impl is gone; teardown is now purely field order (blits and bridge first, GbmDevice last), and the blit SAFETY comments cite that order instead of the previously-false claim. (R4) (R1/R2/R4 from design/pf-zerocopy-sweep-handoff.md.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -166,9 +166,22 @@ pub(crate) unsafe fn compile_shader(kind: u32, src: &[u8]) -> Result<u32> {
|
||||
/// Compile+link the fullscreen-triangle program with fragment source `frag` and bind its `image`
|
||||
/// sampler to texture unit 0.
|
||||
pub(crate) unsafe fn compile_program_with(frag: &[u8]) -> Result<u32> {
|
||||
// Callers retry per frame, so every error path below must delete what it created — a leak
|
||||
// here is unbounded, not one-shot.
|
||||
let vs = compile_shader(GL_VERTEX_SHADER, VERT_SRC)?;
|
||||
let fs = compile_shader(GL_FRAGMENT_SHADER, frag)?;
|
||||
let fs = match compile_shader(GL_FRAGMENT_SHADER, frag) {
|
||||
Ok(fs) => fs,
|
||||
Err(e) => {
|
||||
glDeleteShader(vs);
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let prog = glCreateProgram();
|
||||
if prog == 0 {
|
||||
glDeleteShader(vs);
|
||||
glDeleteShader(fs);
|
||||
bail!("glCreateProgram failed");
|
||||
}
|
||||
glAttachShader(prog, vs);
|
||||
glAttachShader(prog, fs);
|
||||
glLinkProgram(prog);
|
||||
@@ -176,7 +189,10 @@ pub(crate) unsafe fn compile_program_with(frag: &[u8]) -> Result<u32> {
|
||||
glDeleteShader(fs);
|
||||
let mut ok: c_int = 0;
|
||||
glGetProgramiv(prog, GL_LINK_STATUS, &mut ok);
|
||||
ensure!(ok != 0, "GL program link failed");
|
||||
if ok == 0 {
|
||||
glDeleteProgram(prog);
|
||||
bail!("GL program link failed");
|
||||
}
|
||||
glUseProgram(prog);
|
||||
let loc = glGetUniformLocation(prog, c"image".as_ptr());
|
||||
if loc >= 0 {
|
||||
|
||||
Reference in New Issue
Block a user