GstGLContext interop with Rust wgpu - how to get function pointers by name?

Hello! First time poster, long time admirer of GStreamer :slight_smile:

In short: How do I get OpenGL function pointers by name from the GStreamer OpenGL context?

I’m currently trying to figure out how to do OpenGL interop between the Rust wgpu project and GStreamer. I’ve come as far as figuring out that I can create a wgpu instance using the Adapter::new_external in wgpu_hal (sorry, no link, only allowed to add two links).

Here’s an example of how to initialize a wgpu::ExposedAdapter, from an existing OpenGL context:

let exposed = unsafe {
    <hal::api::Gles as hal::Api>::Adapter::new_external(|name| {
        gl_context.get_proc_address(name)
    })
}
.expect("GL adapter can't be initialized");

Now the part that I find tricky is that at some point get_proc_address lands in this function glow::load_all_with_dyn which asks for a bunch of OpenGL function pointers by name, for example:

pub unsafe fn ActiveShaderProgram_load_with_dyn(
    &self,
    get_proc_address: &mut dyn FnMut(*const c_char) -> *mut c_void,
) -> bool {
    load_dyn_name_atomic_ptr(
        get_proc_address,
        b"glActiveShaderProgram\0",
        &self.glActiveShaderProgram_p,
    )
}

Now my question is, what would be the way to get those function pointers by name from the GStreamer OpenGL context?

You can get function pointers by name from a context via gst_gl::GLContext::proc_address(). This gives you an usize but that can be casted to a *mut c_void as needed.

See also the glwindow example and the corresponding helper module. This is using glutin and might give some ideas how to integrate with wgpu too.

Once you have something working between GStreamer and wgpu, it would be great if you could submit an example to the gstreamer-rs repository :slight_smile:

1 Like

Thanks! If I get anything working I’ll look into creating a small example =)

1 Like

I wanted to look into examples/src/bin/glfilter.rs but it only has Linux support.

        #[cfg(not(target_os = "linux"))]
        compile_error!("This example only has Linux support");

I want to develop using macos but target Linux in the end, so I guess I’ll have to do some more digging!

It should work mostly the same on macOS (and Windows), but it needs someone to provide the code and actually ensure that it works.

I did the bare minimum and removed the compiler error line, but quickly ran into a problem regarding the macos core foundation runloop not being Sync

error[E0277]: `*mut core_foundation_sys::runloop::__CFRunLoopSource` cannot be shared between threads safely
   --> examples/src/bin/../glupload.rs:478:30
    |
478 |           bus.set_sync_handler(move |_, msg| {
    |               ---------------- ^------------
    |               |                |
    |  _____________|________________within this `{closure@examples/src/bin/../glupload.rs:478:30: 478:43}`
    | |             |
    | |             required by a bound introduced by this call
479 | |             match msg.view() {
480 | |                 gst::MessageView::NeedContext(ctxt) => {
481 | |                     let context_type = ctxt.context_type();
...   |
512 | |             gst::BusSyncReply::Pass
513 | |         });
    | |_________^ `*mut core_foundation_sys::runloop::__CFRunLoopSource` cannot be shared between threads safely
    |
    = help: within `{closure@examples/src/bin/../glupload.rs:478:30: 478:43}`, the trait `std::marker::Sync` is not implemented for `*mut core_foundation_sys::runloop::__CFRunLoopSource`
note: required because it appears within the type `EventLoopProxy<Message>`
   --> /Users/bes/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.3/src/platform_impl/macos/event_loop.rs:486:12
    |
486 | pub struct EventLoopProxy<T> {
    |            ^^^^^^^^^^^^^^
note: required because it appears within the type `EventLoopProxy<Message>`
   --> /Users/bes/.cargo/registry/src/index.crates.io-6f17d22bba15001f/winit-0.29.3/src/event_loop.rs:393:12
    |
393 | pub struct EventLoopProxy<T: 'static> {
    |            ^^^^^^^^^^^^^^
note: required because it's used within this closure
   --> examples/src/bin/../glupload.rs:478:30
    |
478 |         bus.set_sync_handler(move |_, msg| {
    |                              ^^^^^^^^^^^^^
note: required by a bound in `bus::<impl Bus>::set_sync_handler`
   --> /Users/bes/repos/github/gstreamer-rs/gstreamer/src/bus.rs:193:56
    |
191 |     pub fn set_sync_handler<F>(&self, func: F)
    |            ---------------- required by a bound in this associated function
192 |     where
193 |         F: Fn(&Bus, &Message) -> BusSyncReply + Send + Sync + 'static,
    |                                                        ^^^^ required by this bound in `bus::<impl Bus>::set_sync_handler`

I don’t have much time to dig deeper into this right now unfortunately, but I might come back to it in the coming weeks.

That seems like a bug in winit. AFAIU CFRunLoop is thread-safe:

The functions in Core Foundation are generally thread-safe and can be called from any thread.