New framebuffer broken after dropping another framebuffer on Windows
If I create a framebuffer, drop it, and create a second framebuffer, the second framebuffer is broken. During the call to Framebuffer::new, GL_INVALID_OPERATION is emitted, and the returned framebuffer won't work if you try to render to it. It just looks zeroed out.
This issue went unnoticed while I was on archlinux with a Radeon GPU, but it manifested on my Windows machine which has an old Nvidia Quadro. A friend of mine who also runs Windows tried to run it and got the same errors, but I'm not sure what graphics card that was. Either Nvidia or Intel.
Unfortunately this example isn't ready-to-run code, due to the custom context and logging utils, but hopefully it shows what I'm talking about.
fn new_fb(context: &mut context::Context) -> Framebuffer<GL33, Dim2, RGBA32F, ()> {
Framebuffer::new(context, [0x200, 0x200], 0, Default::default()).unwrap()
}
fn main() {
let event_loop = glutin::event_loop::EventLoop::new();
let mut context = context::Context::new(&event_loop);
let context = &mut context;
glerror::debug_messages(glerror::GlDebugSeverity::Low);
let f = new_fb(context); // No error
drop(f);
new_fb(context);
// GL_INVALID_OPERATION
// GL_INVALID_OPERATION Invalid render buffer.
// GL_INVALID_OPERATION <texture> is not the name of an existing texture.
}
You’re running the master branch?
Yea, maybe I should have mentioned that. Honestly I forgot that I was.
Nah nah it’s all good. I’ll have a look in the day, thanks a lot for notifying!
I hit what sounds like this bug when trying to work with dynamically created framebuffers. In case more reproductions would be useful, here's a patch to examples/common/src/offscreen.rs I came up with to demonstrate it; creating another buffer every frame should be a noop (just wasteful) but instead many frames are black, and the pattern of what is displayed repeats consistently when untouched but sometimes changes if I resize the window or move it to another display (which would be because it triggers the existing recreate-on-resize code).
diff --git a/examples/common/src/offscreen.rs b/examples/common/src/offscreen.rs
index 9da4c64..0d78260 100644
--- a/examples/common/src/offscreen.rs
+++ b/examples/common/src/offscreen.rs
@@ -59,6 +59,7 @@ pub struct LocalExample {
triangle: Tess<Vertex>,
quad: Tess<()>,
offscreen_buffer: Framebuffer<Dim2, RGBA32F, ()>,
+ t: u16,
}
impl Example for LocalExample {
@@ -109,6 +110,7 @@ impl Example for LocalExample {
triangle,
quad,
offscreen_buffer,
+ t: 0,
}
}
@@ -131,13 +133,23 @@ impl Example for LocalExample {
}
}
+ let ref mut alt_buffer: Framebuffer<Dim2, RGBA32F, ()> = context
+ .new_framebuffer([80, 60], 0, Sampler::default())
+ .expect("alt_buffer");
+
+ self.t = self.t.wrapping_add(1);
+ let offscreen_buffer = if self.t % 60 < 30 {
+ &mut self.offscreen_buffer
+ } else {
+ alt_buffer
+ };
+
// we get an object to create pipelines (we’ll need two)
let mut builder = context.new_pipeline_gate();
let program = &mut self.program;
let copy_program = &mut self.copy_program;
let triangle = &self.triangle;
let quad = &self.quad;
- let offscreen_buffer = &mut self.offscreen_buffer;
// render the triangle in the offscreen framebuffer first
let render = builder
The alt_buffer is deliberately low resolution so that successfully using it produces a noticeable visual difference.
Test conditions:
- commit 71f76646199d7aa32887f958d82c1ece63eb82a6 with the above patch
Cargo.lockfreshly recreatedcargo run --bin luminance-examples-desktop -- offscreen- macOS 12.3.1 (21E258) on Intel (not M1); AMD Radeon Pro 5500M
When I was discovering the bug in my own larger code intended for headless rendering, I found that (1) the first run always succeeded, and (2) one of the factors affecting it was whether I used color_slot() vs. into_color_slot(), i.e. whether framebuffers are dropped immediately or later.
I’m going to have a look into it @kpreid , thanks!