-
Notifications
You must be signed in to change notification settings - Fork 51
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
Add wasm-bindgen v0.2 handles for web_sys::HtmlCanvasElement and web_sys::OffscreenCanvas #134
Conversation
Could we expose the regular web-sys types ( |
This would require importing the
|
For what it's worth wgpu tried to use
Could we avoid this by making the web-sys handles type aliases or opaque types that use
Agreed but |
We could likely solve this on our end by making the
This adds a layer of |
At least anecdotally based on my experience removing the use of |
Unless there's a subtlety I'm missing it seems like just wrapping the result of |
My understanding is that it goes something like this because of the ownership transfer that happens when you go through
|
Emphasis mine. As long as the canvas element is never dropped by the other crate there isn't a double drop. It can be either forgotten or wrapped in |
In my example, wgpu wouldn't need the handle anymore so wgpu would drop it, but I thought this would invalidate the ABI handle for future reuse (e.g. passing it to wgpu or another crate). Is my understanding wrong? |
I didn't follow the exact discussion so far, but if you drop the |
To sum up what was discussed in the Matrix room: the idea is that ownership isn't really passed through the The renderer, then, only owns a "reference" to that In chat this was compared to @daxpedda Does this implementation look right? As you're the resident expert on |
As far as I understood the explained implementation, it is correct. It would all be unsafe though until you somehow introduce a lifetime that binds it to the owner of |
I think this is going to miss a common use case then unfortunately. I create a canvas and want to pass it to the graphics system, but I can't guarantee my reference will outlive the usage by the graphics system, so I'll either have to leak it or drop it and break the graphics system. Instead I'd want it to be refcounted like regular |
I know I said:
... in IRC, but this is misleading. When you clone the
I don't know much about RWH, but my impression so far was that this is the same issue other backends have as well. |
Yes, as @daxpedda said the "thing can be double dropped if you aren't careful" problem would not be unique to these handles. Pretty much every resource contained in these window handles have resources associated with them that can't be dropped twice. It's up the the windowing system to own it and the rendering system to not drop it. |
That's true, although temporary canvases are a common pattern for wasm projects (in contrast to native windows which are typically long-lived), especially projects that aren't using a windowing system like winit. Those projects won't be able to use raw-window-handle using this approach without leaking. This would work well if we used web-sys types instead. |
Using the new borrowed handle system it should be possible to parameterize rendering types by the object managing the canvas. This should make it easy from a user perspective to write a wrapper around temporary canvases to work in this manner.
One of the main sticking points for |
Given that there have been no comments on this thread for a while, and that the Web maintainer for I'll give it a week before I do just in case anyone else has any comments. |
In this case you'd want the rendering types to have a strong reference to the temporary canvas in this case, so the rendering types would effectively have to become the owner.
I appreciate trying to be consistent in exposing these handles, and we can proceed with this if people believe it's the best path forward. I'd just like to reiterate that using these ABI handles is:
It would also be unfortunate to add this complexity back into wgpu after recently removing it because of the ownership/borrowing/refcounting challenges the ABI functions caused. The alternative of wrapping web-sys types is what downstream crates would naturally expect, and these types are what people already pass today (if they're not going through raw-window-handle). I feel like the most pragmatic solution is to wrap the web-sys types and having a target-gated dependency, even though it's not consistent with how other handles are exposed1. 1 Although I'd argue other handles would also try to use something better than |
I'll propose another solution: Expose the Something like the following (showing an extension to the hypothetical future of a # Cargo.toml
[dependencies]
web-sys-0-3 = { package = "web-sys", version = "0.3" }
web-sys-0-4 = { package = "web-sys", version = "0.4" } pub struct Wbg02CanvasWindowHandle(Inner);
// Private
enum Inner {
#[cfg(feature = "web-sys-0-3")]
V0_3(web_sys_0_3::JsValue),
#[cfg(feature = "web-sys-0-4")]
V0_4(web_sys_0_4::JsValue),
}
impl Wbg02CanvasWindowHandle {
#[cfg(feature = "web-sys-0-3")]
pub fn new_0_3(js_value: web_sys_0_3::JsValue) -> Self {
Self(Inner::V0_3(js_value))
}
#[cfg(feature = "web-sys-0-4")]
pub fn new_0_4(js_value: web_sys_0_4::JsValue) -> Self {
Self(Inner::V0_4(js_value))
}
#[cfg(feature = "web-sys-0-3")]
pub fn value_0_3(&self) -> Option<js_value: web_sys_0_3::JsValue> {
match self.inner {
Inner::V0_3(value) => Some(value),
_ => None
}
}
#[cfg(feature = "web-sys-0-4")]
pub fn value_0_4(&self) -> Option<js_value: web_sys_0_4::JsValue> {
match self.inner {
Inner::V0_4(value) => Some(value),
_ => None
}
}
} This turns any version mismatch into a runtime error in the consuming library, which may or may not be the better option. |
If we were to go this direction, I would prefer to use I've just realized that the additional downside of including types like that would be that it would make it impossible to release I'll still re-iterate my past points, as even with the proposed model it still becomes increasingly more complicated to construct handles with little added benefit (as the downstream consumer is expected to be using |
Getting this to 1.0 is absolutely a goal. However, we don't need to get the whole crate to 1.0 all at once. Even within rust itself it's common for some parts to stabilize before others (eg: inline asm). We could gate the entire browser handle system behind optional dependencies/features and document it as still experimental even while the rest of the crate for desktop/mobile is moved up to 1.0. If necessary the feature can be called something more generic like |
I would like to avoid using a feature in this case. If we hit 1.0, then |
For what it's worth, this is already the case in most crates that supporting this target, e.g. winit, wgpu, glow, egui's eframe, leptos, etc. all expose |
I don't think a special cfg instead of a cargo feature is very user friendly. Users expect to be able to look at the features list and have it really be the list without secret extra options. As to having a feature that eventually does nothing: It's really not a big deal. If we really wanted we could even remove the feature (since we're not promising the feature is part of our stable API in the first place) if it was really so offense to the sensibilities, but it's the best user experience to just let an opt-in feature "do nothing" once it's eventually part of the default setup. |
Yeah, now that you put it that way. I'll rewrite this PR to use |
Ah wait, So, I think the current implementation of this PR is still the best way of doing it. |
Ah that's too bad. Opened #138 to see if it's worthwhile to consider lifting that. |
cc @grovesNL |
Another argument for keeping Just a thought, I've at least thought about adding support for it in |
It is unlikely to happen, |
The dependency is only present in web targets; I am committed to maintaining |
Signed-off-by: John Nunley <dev@notgull.net>
Even a sys crate usually declares types, and thus can implement appropriate traits on those types. Not that it has to depend on us and do that, but it would be reasonable |
Wasn't a question of "can", but of "should". My impression so far is that This isn't a rule somewhere, so I don't think it's totally unreasonable. |
Signed-off-by: John Nunley <dev@notgull.net>
Signed-off-by: John Nunley <dev@notgull.net>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, thanks @notgull!
Signed-off-by: John Nunley <dev@notgull.net>
// SAFETY: Not using `JsValue` is sound because `wasm-bindgen` guarantees | ||
// that there's only one version of itself in any given binary, and hence | ||
// we can't have a type-confusion where e.g. one library used `JsValue` | ||
// from `v0.2` of `wasm-bindgen`, and another used `JsValue` from `v1.0`; | ||
// the binary will simply fail to compile! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@daxpedda: Do you have a reference for this? How guaranteed is it that there will never be two wasm-bindgen
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not 100% guaranteed.
But generally speaking the way wasm-bindgen
works prevents this, because it encodes "stuff" into the Wasm binary that needs to be interpreted by the CLI tool, so multiple versions will always be incompatible unless wasm-bindgen
becomes a completely different beast.
That said, it was discussed in the past to move wasm-bindgen
to the component model (which isn't stable yet) and drop the CLI completely at some point. This would probably allow multiple versions of wasm-bindgen
to co-exist in the same binary, but old versions will still be unusable. But considering that wasm-bindgen
is not actively developed anymore and there are now things like wit-bindgen
, I doubt this will ever happen.
// the binary will simply fail to compile!
I believe it should compile, but you won't be able to use it. Without the CLI tool it won't work on any runtime and the CLI tool will fail if you have multiple versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to all of your changes @madsmtm
I'd be fine with merging now and bikeshedding later
Closes #102 by adding two new window handles. One represents a
web_sys::HtmlCanvasElement
registered intowasm-bindgen
through its index and the other represents aweb_sys::OffscreenCanvas
in the same way. This allows the handles to contain arbitrary canvases without needing to rely on theid
hack.The main issue with this PR is that the underlying representation for
wasm-bindgen
objects might change to something aside from the current index system. This was raised in rustwasm/wasm-bindgen#1766. However, the index system has remained in place for five years and according to @daxpedda it isn't going anywhere soon. In addition a new system would likely require a breaking change. Therefore we should be fine with this system for the foreseeable future.