Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New framebuffer broken after dropping another framebuffer on Windows #360

Open
iwikal opened this issue Jun 3, 2020 · 5 comments
Open
Labels
analysis required Some more analysis must be taken to fully get the problem / feature. bug:gpu-state A bug that makes the GPU state go invalid. non-reproducible Fully or partially non-reproducible. stale No more activity has occurred for “a while.”

Comments

@iwikal
Copy link
Contributor

iwikal commented Jun 3, 2020

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.
}
@hadronized hadronized added the analysis required Some more analysis must be taken to fully get the problem / feature. label Jun 4, 2020
@hadronized
Copy link
Owner

You’re running the master branch?

@iwikal
Copy link
Contributor Author

iwikal commented Jun 4, 2020

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

@hadronized
Copy link
Owner

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

@hadronized hadronized added bug A bug. bug:gpu-state A bug that makes the GPU state go invalid. and removed bug A bug. labels Jun 5, 2020
@hadronized hadronized added the non-reproducible Fully or partially non-reproducible. label Jul 7, 2020
hadronized added a commit that referenced this issue Oct 28, 2020
@hadronized hadronized added the stale No more activity has occurred for “a while.” label Apr 20, 2021
@kpreid
Copy link
Contributor

kpreid commented May 7, 2022

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 71f7664 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.

@hadronized
Copy link
Owner

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
analysis required Some more analysis must be taken to fully get the problem / feature. bug:gpu-state A bug that makes the GPU state go invalid. non-reproducible Fully or partially non-reproducible. stale No more activity has occurred for “a while.”
Projects
None yet
Development

No branches or pull requests

3 participants