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

Make API fully backend-agnostic #1619

Closed
3 of 5 tasks
blueridanus opened this issue Oct 28, 2017 · 10 comments
Closed
3 of 5 tasks

Make API fully backend-agnostic #1619

blueridanus opened this issue Oct 28, 2017 · 10 comments

Comments

@blueridanus
Copy link

blueridanus commented Oct 28, 2017

This issue tracks progress in making API usage uniform accross backends.

As it currently stands, usage of gfx is still specific to the backend chosen, forcing cross-backend code to be feature gated – see examples/hal/quad:


To-do:

  • Different entry point name for Metal:
// MSL doesn't allow `main` entry point name.
//TODO: just use a different name consistently in all backends
#[cfg(feature = "metal")]
const ENTRY_NAME: &str = "main0";
#[cfg(not(feature = "metal"))]
const ENTRY_NAME: &str = "main";
        //TODO: remove the type annotations when we have support for
        // inidirect argument buffers in SPIRV-Cross
        #[cfg(any(feature = "vulkan", feature = "dx12", feature = "metal", feature = "gl"))]
        let (vs_entry, fs_entry) = (
            pso::EntryPoint::<back::Backend> { entry: ENTRY_NAME, module: &vs_module },
            pso::EntryPoint::<back::Backend> { entry: ENTRY_NAME, module: &fs_module },
        );

        #[cfg(all(feature = "metal", feature = "metal_argument_buffer"))]
        let (vs_entry, fs_entry) = (
            pso::EntryPoint { entry: "vs_main", module: &shader_lib },
            pso::EntryPoint { entry: "ps_main", module: &shader_lib },
);
  • Autorelease pool for Metal:
#[cfg(feature = "metal")]
    let mut autorelease_pool = unsafe { back::AutoreleasePool::new() };
  • Different window creation for OpenGL:
   #[cfg(any(feature = "vulkan", feature = "dx12", feature = "metal"))]
    let window = wb
        .build(&events_loop)
        .unwrap();
    #[cfg(feature = "gl")]
    let window = {
        let builder = back::config_context(
            back::glutin::ContextBuilder::new(),
            ColorFormat::SELF,
            None,
        ).with_vsync(true);
        back::glutin::GlWindow::new(wb, builder, &events_loop).unwrap()
};
  • Different backend instantiation for OpenGL:
    #[cfg(any(feature = "vulkan", feature = "dx12", feature = "metal"))]
    let (_instance, mut adapters, mut surface) = {
        let instance = back::Instance::create("gfx-rs quad", 1);
        let surface = instance.create_surface(&window);
        let adapters = instance.enumerate_adapters();
        (instance, adapters, surface)
    };
    #[cfg(feature = "gl")]
    let (mut adapters, mut surface) = {
        let surface = back::Surface::from_window(window);
        let adapters = surface.enumerate_adapters();
(
// Setup renderpass and pipeline
    #[cfg(any(feature = "vulkan", feature = "dx12", feature = "metal"))]
    let vs_module = device
        .create_shader_module(include_bytes!("data/vert.spv"))
        .unwrap();
    #[cfg(any(feature = "vulkan", feature = "dx12", feature = "metal"))]
    let fs_module = device
        .create_shader_module(include_bytes!("data/frag.spv"))
        .unwrap();

    #[cfg(all(feature = "metal", feature = "metal_argument_buffer"))]
    let shader_lib = device.create_shader_library_from_source(
            include_str!("shader/quad_indirect.metal"),
            back::LanguageVersion::new(2, 0),
        ).expect("Error on creating shader lib");

    #[cfg(feature = "gl")]
    let vs_module = device
        .create_shader_module_from_source(
            include_bytes!("shader/quad_150.glslv"),
            pso::Stage::Vertex,
        ).unwrap();
    #[cfg(feature = "gl")]
    let fs_module = device
        .create_shader_module_from_source(
            include_bytes!("shader/quad_150.glslf"),
            pso::Stage::Fragment,
).unwrap();
@kvark
Copy link
Member

kvark commented Oct 29, 2017

Thanks for filing a nicely detailed issue, way to go!
FYI, metal_argument_buffer is sort of unusable now, blocked on KhronosGroup/SPIRV-Cross#293
For GL, there are differences in the initialization, but that's fine by me. We'll try to narrow them down in #1539, but this is low-priority, especially given that GL backend itself is not yet functional :)
If you exclude these two, the only things left are Metal entry point names and auto-release pool.

@grovesNL
Copy link
Contributor

Entry point names should be fixed by #1627 (except metal_argument_buffer which is blocked)

@kvark
Copy link
Member

kvark commented Apr 26, 2018

The only point left here, really, is GL initialization.

@goddessfreya
Copy link
Contributor

So, I've been looking into possible methods of merging the OpenGL instantiation
code with the rest so that we can use it with Portability, and I think I got a
couple possible methods:

1- We can just spawn our own new events loop and create a headless context with
it. I'm pretty sure this would ruin macOS compatibility. Also, the winit/glutin
guys recommend against having multiple events loops, so hopefully this finds it
self as a last resort.

2- We could somehow make the context based on the window we get when making the
surface. Not really sure if it's possible, but I guess we could try. Not sure
how we'd handle calls before we got the surface made. Store then in a vector
maybe and do them when the surface is made?

3- According to this we can use the Desktop window, as long as we don't try to
render to it: link. Probably do the whole one context per window thing I tried
before, only this time the main context won't need an events loop to make. This strikes
me as the most promising method so far.

@goddessfreya
Copy link
Contributor

goddessfreya commented Jul 15, 2018

To expand on method 3:

We can get the default window in X11 using XDefaultRootWindow (Tested). In windows by GetDesktopWindow (untested). In wayland via egl.GetDisplay(ffi::egl::DEFAULT_DISPLAY as *mut _) (tested). Of course, I have no clue about macs.

We also need other stuff, like an XConnection for X11 (of course we can make that). Using method 3 will also require a major refactoring of glutin. The main context won't be okay to share with other contexts (*). We of course shouldn't try to draw stuff when using that context. (e.g. Wayland panics with an InvalidOperation).

Here is the hacks to glutin which I used for testing:https://gist.github.com/ZeGentzy/b89b13c108d7242b8a4608cac59f063b

Since we can't share stuff, we probably will have to store every call they made before they made a surface. Do them on our main context when they haven't made a surface. Then do them again we they make the (first?) surface for that window (**). We'd have to map the handles they got from before they made the surface to the potentially different handles post-surface. Things supported on the main context might be unsupported on the new one, and vice versa.

(*) If we make our context with the same API as theirs we will be okay. Issue is, we don't know what they'll use. Also, even if we did, we still have no control over whether or not they share their context with ours, when using portability. Actually, we'll have to make the contexts for their windows. So this we do control. I guess method 3 is just method 2 with additional support for function calls before they make their surface. We'll still have to store function calls for things which arent shared between contexts. We'd have to map the handles they got from before they made the surface to the potentially different handles post-surface ONLY for those non-shareable things. Things supported on the main context might be unsupported on the new one, and vice versa? Actually, we can probably (haven't tested it tho) render to a framebuffer backed by a texture, then blit the texture to the created window's frame buffer, just as my previous attempt was doing.
(**) And redo them for every (first?) surface they make for every other window too, assuming we ever support more than one window.

@goddessfreya
Copy link
Contributor

From the looks of it, Headless Contexts in macos don't even need a window. I guess we'd just have to wait for rust-windowing/glutin#1029 in the mac department.

@fu5ha
Copy link
Contributor

fu5ha commented Aug 2, 2018

@zegentzy any update on this?

@goddessfreya
Copy link
Contributor

goddessfreya commented Aug 2, 2018

@termhn I'm actively working on the changes to glutin and winit which I think will be necessary for merging the backends. Currently looking to add a way to create winit's event loops and windows from their (or a subset of their) raw parts.

@goddessfreya
Copy link
Contributor

It's been nearly a month of dicking around in my spare time but I have finally put together rust-windowing/glutin#1058 and all the other PRs it depends on for linux. Soon the backends will be combined (on linux)!

Insert evil laugh here.

@kvark
Copy link
Member

kvark commented Dec 3, 2020

Let's consider this closed by #3506 🎉

@kvark kvark closed this as completed Dec 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants