gtk-rs / gtk3-rs

Rust bindings for GTK 3
https://gtk-rs.org
MIT License
508 stars 90 forks source link

GLContext integration #94

Open gkoz opened 8 years ago

gkoz commented 8 years ago

There currently is no reliable way to use the glium/gl crates together with GLContext (and gtk::GLArea), which a very limited API. Previous discussion is at https://github.com/gtk-rs/examples/pull/44, let's continue it here.

gkoz commented 8 years ago

@mjkoo

Either way to me it looks like GtkGLArea creates a context for you, but relies on you to correctly infer the correct way to load and use OpenGL functions after initialization, so the same type of logic with the same type of assumptions probably needs to go somewhere to make this usable.

What would happen if we gave epoxy_get_proc_address to gl::load_with?

mjkoo commented 8 years ago

Pretty sure that should work, I can give it a try in a bit to confirm. That seems to be about half of what epoxy provides, the other half is autogenerated wrappers around OpenGL functions which load the required symbols at runtime lazily. This is pretty much exactly what gl-rs does AFAICT, so we don't necessarily care about that. Given that, not sure if it would make more sense to make bindings and add in a dependency to libepoxy or just use FFI to call the underlying glx/wgl/egl functions based on the target platform in the same manner epoxy and glutin does.

gkoz commented 8 years ago

I'd favor adding limited bindings over replicating libepoxy logic.

I'm also unsure if gdk_gl_context_set_required_version and gdk_gl_context_set_forward_compatible can influence the selection of gl* functions in a problematic way or just let you get an error if the implementation is incompatible.

gkoz commented 8 years ago

It might be possible to look for the epoxy_get_proc_address symbol on demand at runtime instead of adding a dependency.

mjkoo commented 8 years ago

Looking into it now, one issue is that epoxy_get_proc_address is not exposed by libepoxy, likely because it takes some bootstrapping to get it working, which we would also need to make sure gets done prior to using it even if we expose it. We could instead try to load libepoxy at runtime like you said and have gl::load_with attempt to dlsym the equivalent symbols from libepoxy. This is somewhat janky because now there's two levels of symbol lookup and function pointer caching being done, but it looks like not doing that will involve a considerable amount of tearing libepoxy apart.

mjkoo commented 8 years ago

Regarding gdk_gl_context_set_required_version and gdk_gl_context_set_forward_compatible, it looks like they just influence the parameters passed to glXCreateContextAttribsARB from gdk (https://github.com/GNOME/gtk/blob/master/gdk/x11/gdkglcontext-x11.c#L578), which should result in calling an invalid function returning an error code according to https://open.gl/context , so this shouldn't be a worry I think.

Diving into the gdk source it looks like they themselves already depend on libepoxy and use it to set up the context behind the scenes, so that's good news. Do you know of a relatively platform-independent way to dlsym or similar from rust to get at the epoxy_* wrappers from gl-rs?

gkoz commented 8 years ago

I'm only aware of unstable std::dynamic_lib. FWIW, GTK relies on dlfcn-win32 to provide dlsym on Windows.

mjkoo commented 8 years ago

Pushed a PoC of the example from https://github.com/gtk-rs/examples/pull/44 back to the same branch, now loading OpenGL function addresses from epoxy, relying on it being loaded already by gdk. Uses the shared_library crate which is also used in glutin (std::dynamic_lib is deprecated according to rustc I guess).

This is not correct as it stands, as I'm pretty sure gl-rs's caching of function pointers means that it will always invoke the libepoxy lookup function even when epoxy has already resolved the address and altered it's internal function pointer table resulting in many superfluous dlsym invocations, but is a start.

mjkoo commented 8 years ago

After researching it a bit, I think the best way forward is to use gl_generator from gl-rs with a custom generator to wrap libepoxy and let it handle lookup and caching of the relevant functions when using it with GdkGLContext. I've modified the StaticStructGenerator from gl_generator to generate bindings for epoxy in a build.rs, and modified the example again to use this new method (https://github.com/mjkoo/examples/tree/epoxy-glgenerator) This supports the goal of integrating with glium, as it uses the similar StructGenerator to construct it's own bindings, but using the get_proc_address from glutin or similar.

Wanted to get some thoughts on this before moving forward, but I'm thinking that the build.rs from the branch above can be cleaned up and put into gdk, and the epoxy wrapper struct made accessible from GdkGLContext. A GtkGLArea user can then use the reference to the context in its render handler and can use this to draw to its window.

gkoz commented 8 years ago

Oh wow, that's some sudden explosion of complexity :)

If generating epoxy bindings is the way to go, that's outside the scope of gdk. In the near term you'd probably want to put an epoxy-gl crate on github and import that in the example.

and the epoxy wrapper struct made accessible from GdkGLContext

From what I can see there's nothing but magical side-effects to tie a particular GLContext instance to the gl* impls, so I'm not sure what the GLContext/GLArea bindings could do except reexport the epoxy bindings.

Perhaps the best solution would be to ignore the whole epoxy/GLContext/GLArea stack and implement a new widget, that would really be in control of its context. Like, wrap the window primitive, that glium creates, in a GdkWindow or vice versa.

mjkoo commented 8 years ago

Okay sure, crate is up and example is updated.

From what I can see there's nothing but magical side-effects to tie a particular GLContext instance to the gl* impls, so I'm not sure what the GLContext/GLArea bindings could do except reexport the epoxy bindings.

Yep, I agree with that assessment. Using the epoxy bindings though should allow us to get some integration going with glium now, perhaps with a small modification to glium to allow generic gl::Gl type structs in glium::context::Context (epoxy::Gl should be a drop-in replacement). If @tomaka isn't for that, potentially a small get_proc_address-like shim could be added to epoxy to allow interop with gl/glium without running into the function pointer caching issue. Will keep exploring down these lines for the time being.

mjkoo commented 8 years ago

As an update, I've ported the simple example from the examples repo to use glium with a GLArea. There's definitely some cleanup to do and some decisions on where things belong, but it seems to work. The work in progress code can be found at https://github.com/mjkoo/examples/tree/glium

gkoz commented 8 years ago

That's impressive progress :) FWIW it seems GLContext can be made capable of telling if it's current (by comparing what gdk_gl_context_get_current returns with itself) and the dimensions could be retrieved from its GdkWindow.

swap_buffers... it appears the window painting mechanisms take care of swapping the buffers. Wouldn't queue_render there lead to constant repainting?

mjkoo commented 8 years ago

Thanks! Cool that's good to know, I will change is_current accordingly and try it out. Spot on with your comment on swap_buffers, I actually just fixed that up :)

I'm thinking that once the Backend and Facade implementations are looking good they probably also belong in a separate crate, similar to glium_sdl2, unless you'd like to see this put into gdk somewhere?

gkoz commented 8 years ago

I will change is_current accordingly and try it out

This will require patching gdk as I don't think PartialEq/Eq is implemented for objects. Not even sure if it would be appropriate in general to implement it as pointers equality. Specialization will make that decision easier :)

I'm thinking that once the Backend and Facade implementations are looking good they probably also belong in a separate crate, similar to glium_sdl2, unless you'd like to see this put into gdk somewhere?

Still not sure but a separate crate is a good bet.

mjkoo commented 8 years ago

Ok cool I will defer doing that for now then, let me know what you'd like to see going forward.

gkoz commented 8 years ago

A separate crate seems more flexible, we wouldn't need to track changes to glium and epoxy in the gdk and gtk crates and it wouldn't matter that GLArea and GLContext are in different crates.

phrohdoh commented 6 years ago

Hey @mjkoo - sorry for digging up an old thread!

Has there been any progress on this front? (another crate being spawned or something similar)

I'd really like to use glium in some of my gtk apps. :-}

mjkoo commented 6 years ago

Sorry I ended up going a different route for the project that I was working on and therefore didn't pursue this further, not sure what the glium + gtk story is today.

lattice0 commented 2 years ago

What is the state of this? Wanted to render into Flutter which uses GTK, it gives me a GTKWindow and GdkGlContext. Works in C++ so should work in Rust