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

wasm-unknown-unknown support #1167

Open
StevenDoesStuffs opened this issue Jun 9, 2019 · 18 comments
Open

wasm-unknown-unknown support #1167

StevenDoesStuffs opened this issue Jun 9, 2019 · 18 comments

Comments

@StevenDoesStuffs
Copy link

Are there any plans to support the wasm-unknown-unknown target with wasm-bindgen? That seems to be where most of the community is headed.

@goddessfreya
Copy link
Contributor

If someone wants to do it, I'll be happy to accept it.

@goddessfreya
Copy link
Contributor

@goddessfreya goddessfreya added this to the Eventsloop milestone Jun 20, 2019
@goddessfreya goddessfreya pinned this issue Jul 17, 2019
@est31
Copy link
Contributor

est31 commented Aug 4, 2019

@TannerRogalsky
Copy link

I'm working on this. If it's been two weeks and there's no update assume I'm lost at sea and ping me.

@TannerRogalsky
Copy link

Let's consider the difference between winit's "emscripten" and "web" Window structures, respectively.

#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowId(usize);

impl WindowId {
    pub unsafe fn dummy() -> Self {
        WindowId(0)
    }
}

pub struct Window2 {
    cursor_grabbed: Mutex<bool>,
    cursor_visible: Mutex<bool>,
    is_fullscreen: bool,
    events: Box<Mutex<VecDeque<::Event>>>,
}

pub struct Window {
    window: Arc<Window2>,
}
mod backend {
    pub struct Canvas {
        raw: HtmlCanvasElement,
        ...
    }
}

pub struct Window {
    canvas: backend::Canvas,
    previous_pointer: RefCell<&'static str>,
    position: RefCell<LogicalPosition>,
}

In many ways I think that the web one is better.

The emscripten struct maintains no identifying information. The emscripten implementation, when asked for it's id, always returns 0. When setting HTML state, the emscripten implementation either uses an API that doesn't specify a target or passes a null pointer (both of these actions result in emscripten falling back to it's own internally-tracked reference to the canvas object).

The web one maintains a reference to the canvas object. The creation function creates the canvas element. It's not clear to me where (or if) that gets inserted into the document (it's possible that that's beyond glutin's scope). State queries and modifications act on that reference.

Where this falls down is that glutin requires that Context implement Send + Sync. At it's core, the Canvas reference (via wasm_bindgen::JsValue) is backed by a *mut u8 which... presents some thread-safety issues.

The easiest solution is to modify the web implementation to maintain a singleton reference outside of it's struct. It's bad but it's bad in a similar way to how the emscripten implementation is bad. Better solutions aren't coming to me right off the bat. But maybe posting this will spark some conversation. Either way I will try the easy way and report back.

@TannerRogalsky
Copy link

I haven't given up on this but I'm expanding my thesis a bit. Bear with me.

@TannerRogalsky
Copy link

So there are two outstanding issues that I see with bringing wasm32-unknown-unknown support to glutin.

Firstly, as outlined above, glutin's requirement that the window context implement the synchronization traits is problematic with regards to the web. References to a canvas element (or any JS references for that matter) cannot be shared between threads. There are definitely hacks to get around this but that would mean that glutin's API is writing checks that it's implementation can't cash. An honest implementation for the web will require a relaxation of those trait requirements.

Secondly, one of the primary benefits from using this library is being able to initialize a GL context via get_proc_address. While it's likely possible to replicate that functionality with WebGL, the API differences between OpenGL and WebGL will require awareness from the calling code anyway so the point is, I think, moot.

Between these two issues, I'm not sure bringing wasm32-unknown-unknown support to glutin is valuable.

That said, winit's web improvements + glow together offer what I think is a compelling replacement on web.

@goddessfreya
Copy link
Contributor

I'm not familiar with how how get_proc_address would work w/ web, as I have no knowledge wrt wasm-unknown-unknown.

As for the requirement of Sync + Send, we could just not implement FailToCompileIfNotSendSync on Context<NotCurrent> on web. I'm pretty sure JS does not support multi threading, altho I'm not precisely sure how it works wrt wasm-unknown-unknown.

@TannerRogalsky
Copy link

Implementing get_proc_address can be made to work. There currently aren't any crates that I'm aware of that could take advantage of that on web because the way that WebGL bindings are loaded and used is significantly different from OpenGL. I suppose that's a chicken and the egg problem, though, so that's not necessarily a non-starter.

Yeah, relaxing the requirements for that trait from being global to being native-only would resolve the first problem. Really, it should be relaxed for web platforms, though, including emscripten. Does that sound reasonable to you?

@agausmann
Copy link

WebGL is fundamentally binary-incompatible with OpenGL. It's a JavaScript API, with quite a few differences. It would require an OpenGL implementation that acts as a translation layer, which is what emscripten does.

I'm currently working on a crate that would provide a similar thing, but as a standalone library that works on wasm32-unknown-unknown, if you are interested in following its progress and/or contributing. It's not completely conformant yet, though I do have some working demos, and I'm actively working on compatibility issues as I find them.

@alvinhochun
Copy link

What about adding optional integration with glow instead? glutin can add a function to retrieve a glow context, which will internally use glow::Context::from_loader_function and get_proc_address on native platforms, but use HtmlCanvasElement::get_context("webgl2") and glow::Context::from_webgl2_context (or webgl1) on wasm32 + web-sys.

@caiiiycuk
Copy link

+1 for glow, it also supports wasm-unknown-emscripten

@kchibisov
Copy link
Member

This should be reiterated, given that winit is not involved anymore.

@notgull
Copy link
Member

notgull commented Apr 26, 2023

I would support having a way to return a glow context. Anything else would require us to build a shim between WebGL and OpenGL... which glow already does pretty well.

The only issue is that glow is an unstable crate, meaning that if it has a breaking change, we have to have a breaking change too. Then again, it's not like we're hitting 1.0 anytime soon either.

@kchibisov
Copy link
Member

Well, glutin will likely hit v1.0.0 relatively soon, because nothing really changes that much in OpenGL field.

We can probably have some sort of a shim between us and glow, so the glow wouldn't be exposed.

@notgull
Copy link
Member

notgull commented Jul 9, 2023

cc glium/glium#2060 (comment)

@grovesNL Are you planning on making any breaking changes to glow at any point in the near future? If not I was planning on taking a run at this.

@kchibisov
Copy link
Member

Some summary from the IRC, at least my points on how it could be done.

If we plan on having web target along other backends, we could do the following:

  • The GlDisplay could be created the same way as on windows, so requiring RawWindowHandle.
  • GlContext could be created only PossiblyCurrentContext and we disallow to creation of NotCurrent, we also don't allow recreating the context until you drop it, but you'll get the same context... (I think it's some sort of singleton, correct me if I'm wrong)
  • The GlSurface could be some opaque type with just RawWindowHandle, same as on macOS.
  • The get_proc_address on the display should work with web-sys functions and rely on reflection, not sure how could it'll work out, but the goal could be for glow to simply take address of functions it wants out of it. The hardest part here is obviously a gl_generator like API, but maybe we should suggest to rely on glow here to do the loading.
  • GlConfig not sure what to do about this one...

The most complicated part is to setup the glue for the get_proc_address in a sensible way so glow can actually use it instead of its own internal function loading on the web.

I'm not quite sure how extensions work here, maybe a special method could be needed for web to query for certain extensions. Maybe we should change the extensions API in general to be more Query oriented instead of just listing everything.

However, maybe we don't need to handle web specifically? Users doing web likely has separate code to initialize the web platform and they could create the glow context there, and if they have native code, they could use glutin for that and cfg it out in their gl platform init code.

cc @grovesNL , since they know WebGl and likely could say whether it's even worth to try add all of that to glutin. I'm myself not that certain.

@TannerRogalsky
Copy link

However, maybe we don't need to handle web specifically? Users doing web likely has separate code to initialize the web platform and they could create the glow context there, and if they have native code, they could use glutin for that and cfg it out in their gl platform init code.

This is exactly how I've seen things done. A main.rs-style binary creates a windows for native platforms and a conditionally compiled web.rs module exports initializers that take a canvas element on JS. Both then deal with the primary implementation in lib.rs that only uses a glow::Context.

The most useful thing for me (if I could provide a single data point) would be a mapping of GlConfig attributes to their web counterparts. That would de-duplicate most of the configuration of the surface which is the significant part of the unique-per-platform code right now.

But take that with a huge grain of salt because I haven't seriously considered what that would entail. Nor do I think it's a major stumbling block as it's sort of "write it once and forget it" code. Nor do I really think that glutin would be a good home for that mapping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

9 participants