luminance-rs icon indicating copy to clipboard operation
luminance-rs copied to clipboard

New framebuffer broken after dropping another framebuffer on Windows

Open iwikal opened this issue 5 years ago • 5 comments

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.
}

iwikal avatar Jun 03 '20 22:06 iwikal

You’re running the master branch?

hadronized avatar Jun 04 '20 08:06 hadronized

Yea, maybe I should have mentioned that. Honestly I forgot that I was.

iwikal avatar Jun 04 '20 10:06 iwikal

Nah nah it’s all good. I’ll have a look in the day, thanks a lot for notifying!

hadronized avatar Jun 05 '20 10:06 hadronized

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.lock freshly recreated
  • cargo 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.

kpreid avatar May 07 '22 19:05 kpreid

I’m going to have a look into it @kpreid , thanks!

hadronized avatar May 09 '22 16:05 hadronized