-
Notifications
You must be signed in to change notification settings - Fork 40
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
Renderer API Wrapper #22
Conversation
The events example no longer builds because of the removal of |
If you can also provide an example using the new render api wrapper, that would be very helpful for a newcomer like me :D. |
I think most commits can be squashed into one (the fixups by definition of course), but probably the following ones as well (unless each commit is meaningful on its own). I'd put a potential example into a separate commit maybe. |
I just looked into it a bit, and I'm not sure how this example is even supposed to work. There are two separate threads that reference the same I think this happened due to the lifetime changes, making this example really hard to get to work in the way it's supposed to. |
Well, it was way more work than I anticipated, but I added a working example. The biggest problem was that I had to combine two event loops, mpv's and glutin's (which just wraps winit). In order to avoid idle polling (which isn't an issue for my own project, since I'm doing stuff during that time anyways), I had to wrap two more mpv APIs, the render update callback and the wakeup callback. However, the example is now quite clean, it only polls events and redraws the window when actually necessary. I also had to fix another bug in the process, the |
Made RenderContext accessible from outside the crate. Cleaned up EventContext lifetime issues. Fixed a ton of warnings and undefined behavior.
…the rendered image to a framebuffer.
I've done a squash where it makes sense. I'm a fan of having smaller commits, I hope it's ok this way. |
One remaining issue is that the renderer context has to be dropped before the mpv player itself. Currently this cannot be verified by the compiler, so some restructuring might be needed (such as the mpv player owning the renderer). |
Hi, Regarding
and
You restructued the |
It's been a hot minute since I changed that, so I don't remember exactly why I did it, but I think it was because it was impossible to store the |
With these changes ( The main reason I had in mind when designing Alternatively we could create a method that, when notified of new events, calls wait_event internally until no new events exist, and then passes a |
No you can't, because this is running on an internal thread where you're not allowed to do much. This is why I had to resort to user events in the example, because even calling Now that I write this, I realize that the callback closures have to be Anyways, since the crate doesn't know anything about the application setup, it can't message the main thread about calling
In order to do this, you'd have to move the instance into the closure, which would make it impossible to use it elsewhere (like the actual drawing call). This restriction might be tricked by wrapping it in an Unfortunately, handling multithreaded C APIs is always a mess in Rust, because C APIs tend to be pretty free-form in what you're allowed to do. There might not be a perfect way to explain to the Rust compiler what's allowed in the wakeup closure and what's not possible. What would be possible is to set a thread-local variable to true while executing the callbacks, and then check in every Mpv function whether that flag is true and panic if it's the case. However, accessing thread-local data adds a lot of overhead to calls. |
Hmm maybe I should actually try that thing with |
Hi /*
[dependencies]
fltk = {version = "1.1", features=["enable-glwindow", "no-pango"]}
libmpv = { git = "https://github.com/anlumo/libmpv-rs" }
*/
use fltk::{enums::Mode, prelude::*, *};
use libmpv::{
render::{OpenGLInitParams, RenderContext, RenderParam, RenderParamApiType},
FileState, Mpv,
};
use std::os::raw::c_void;
pub fn get_proc_address(win: &window::GlutWindow, name: &str) -> *mut c_void {
win.get_proc_address(name) as _
}
fn main() {
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
println!("Usage: mpv <video file>");
std::process::exit(1);
}
let a = app::App::default().with_scheme(app::Scheme::Gleam);
app::get_system_colors();
let mut win = window::Window::default().with_size(800, 600);
let mut mpv_win = window::GlutWindow::new(5, 5, 790, 530, None);
mpv_win.set_mode(Mode::Opengl3);
let mut btn = button::Button::new(360, 545, 80, 40, "@||");
win.end();
win.make_resizable(true);
win.show();
mpv_win.make_current();
let mut mpv = Mpv::new().expect("Error while creating MPV");
let render_context = RenderContext::new(
unsafe { mpv.ctx.as_mut() },
vec![
RenderParam::ApiType(RenderParamApiType::OpenGl),
RenderParam::InitParams(OpenGLInitParams {
get_proc_address,
ctx: mpv_win.clone(),
}),
],
)
.expect("Failed creating render context");
mpv.event_context_mut().disable_deprecated_events().unwrap();
mpv.playlist_load_files(&[(&args[1], FileState::AppendPlay, None)])
.unwrap();
btn.set_callback(move |b| {
let prop: bool = mpv.get_property("pause").unwrap();
mpv.set_property("pause", !prop).unwrap();
if prop {
b.set_label("@||");
} else {
b.set_label("@>");
}
});
mpv_win.draw(move |w| {
render_context
.render::<window::GlutWindow>(0, w.w() as _, w.h() as _, true)
.expect("Failed to draw on GlutWindow");
w.swap_buffers();
});
app::add_idle(move || {
mpv_win.redraw();
});
a.run().unwrap();
} |
Nice! Note that you're probably spinning in a tight loop redrawing the same image over and over again in your draw closure, until there's a new one available from the video. |
How is this coming along? I have found that the fork consistently throws segfaults when used with OpenGl when creating RenderContext on Windows 10 using mpv-dev-x86_64-1.109. I have tried out the software renderer - which unsurprisingly works - but that's hardly an alternative for resolutions larger than HD |
Btw, debugging tells me that that segfault happens in gpa_wrapper when calling params.get_proc_address, whose pointer is 0xabababababababab. When RenderContext::new is called, the structure is still valid. When the params arrive at gpa_wrapper, the layout seems invalid. |
See:
|
Fixed version:
|
I added a few APIs and fixed the memory management. Now it's actually working with OpenGL for me!
It is based on #20.