hadronized / luminance-rs

Type-safe, type-level and stateless Rust graphics framework
https://phaazon.github.io/learn-luminance/
Other
1.09k stars 59 forks source link

[luminance-glutin] How to make use of glutin:WindowedContext #580

Closed fralonra closed 2 years ago

fralonra commented 2 years ago

Hi, thanks for this awesome library.

I'm a newbie to Rust, and have problems on how to make use of glutin:WindowedContext alone with luminance-glutin crate.

Below is the minimum code:

// imports...

fn main_loop(mut surface: GlutinSurface, el: event_loop::EventLoop<()>) {
    let ctx = unsafe { surface.ctx.make_current().unwrap() };
    let back_buffer = surface.back_buffer().unwrap();
    el.run(move |event, _, control_flow| match event {
            Event::RedrawRequested(_) => {
                let render = surface
                    .new_pipeline_gate()
                    .pipeline(
                        &back_buffer,
                        &PipelineState::default(),
                        |_, _| { Ok(()) }, // rendering here...
                    )
                    .assume();
                if render.is_ok() {
                    surface.swap_buffers();
                }
                // example usage of glutin:WindowedContext
                ctx.window().request_redraw();
            }
            _ => (),
        }
    );
}

fn main() {
    let wb = window::WindowBuilder::new()
        .with_title("App")
        .with_inner_size(dpi::LogicalSize::new(1024.0, 768.0));
    let surface = GlutinSurface::new_gl33(wb, 0);

    match surface {
        Ok(surface) => {
            eprintln!("graphics surface created");
            main_loop(surface.0, surface.1);
        }
        Err(e) => {
            eprintln!("cannot create graphics surface:\n{}", e);
            exit(1);
        }
    }
}

However, the code gave me the following error: borrow of partially moved value: surface and I've no idea how to correct it.

I need GlutinSurface to be used in some GL stuff and glutin:WindowedContext to handle glutin things as well.

Is there anyone can help me with this? Thanks!

fralonra commented 2 years ago

At last, I did something like this:

fn main_loop(mut surface: GlutinSurface, el: event_loop::EventLoop<()>) {
    // remove the following line.
    // let ctx = unsafe { surface.ctx.make_current().unwrap() };
    // ...
    el.run(move |event, _, control_flow| match event {
            Event::RedrawRequested(_) => {
                // rendering code.
                // changing code to these:
                let ctx = &surface.ctx;
                ctx.window().request_redraw();
            }
            _ => (),
        }
    );
}

It somehow worked.

But I still wonder what is the typical solution to this problem.

geom3trik commented 2 years ago

I believe you are getting the error because surface.ctx.make_current() will move the inner context out. Then inside the event loop you are trying to use surface which has been partially moved. Instead, try calling ctx.swap_buffers().

You definitely don't want to leave out the line which makes the context current, though it looks like maybe it makes it current for you on creation if it's working without that line.

fralonra commented 2 years ago

I believe you are getting the error because surface.ctx.make_current() will move the inner context out. Then inside the event loop you are trying to use surface which has been partially moved. Instead, try calling ctx.swap_buffers().

You definitely don't want to leave out the line which makes the context current, though it looks like maybe it makes it current for you on creation if it's working without that line.

@geom3trik Thanks for your reply!

ctx.swap_buffers is convenient but in this pattern there are still some problems. The final working code piece looks like these:

fn main_loop(mut surface: GlutinSurface, el: event_loop::EventLoop<()>) {
    // ...
    el.run(move |event, _, control_flow| match event {
            Event::RedrawRequested(_) => {
               let back_buffer = &surface.back_buffer().unwrap();
               let render = surface
                    .new_pipeline_gate()
                    .pipeline(
                        &back_buffer,
                        &PipelineState::default(),
                        |_, _| Ok(()), // rendering here...
                    )
                    .assume();
                if render.is_ok() {
                    surface.swap_buffers();
                }
                // changing code to these:
                let ctx = &surface.ctx;
                ctx.window().request_redraw();
            }
            _ => (),
        }
    );
}

If I keep the code that makes the context current, an error would thrown as it conflicts with both the code to get back buffer and the pipeline gate.