-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Experimental WebGL wgpu backend support #1096
Conversation
futures/src/runtime.rs
Outdated
@@ -5,6 +5,50 @@ use crate::{subscription, Executor, Subscription}; | |||
use futures::{channel::mpsc, Sink}; | |||
use std::marker::PhantomData; | |||
|
|||
#[cfg(not(target_arch = "wasm32"))] |
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.
Instead of duplication of Runtime
and Tracker
with the different trait bounds, but I thought that such trait aliasing may work better WYT?
Opening PR for review, looks like an issue with text rendering is not directly related to |
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! Will take a proper look soon 🎉
Instead of a new example, could we instead change the existing one so it works everywhere?
@hecrj Actually yes I will do that, I just need to figure out alternative |
@hecrj made original |
UPD: Just a thing to consider - this example works fine with |
@pacmancoder Yes, I think we can remove the SPIR-V shaders altogether and use |
Removed spir-v shader and fixed code formatting (GH Workflow was failing in cargo fmt) |
@hecrj is something still blocking this PR before merge? |
This is great! I was about to implement the same thing before I found this. I'll take a look now as well and let you know if I find some issues. |
winit/src/clipboard.rs
Outdated
#[cfg(target_arch = "wasm32")] | ||
pub struct Clipboard; | ||
|
||
#[cfg(target_arch = "wasm32")] |
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.
When I tried to get this to work yesterday, I added a "NullClipboard" to window_clipboard
instead. We can eventually replace it with proper clipboard support for different wasm environments. I think this is cleaner than having a feature flag here, but not sure what @hecrj prefers.
Can send a pull request if my approach is more descired
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.
I took another quick glance and left some more feedback.
I still have to take a proper look and test everything! However, I'm working on a bunch of changes related to rendering and I'd like to finish that first.
futures/src/subscription/tracker.rs
Outdated
#[cfg(not(target_arch = "wasm32"))] | ||
mod trait_aliases { | ||
use super::*; | ||
|
||
pub trait TrackerMessage: Send + 'static {} | ||
|
||
impl<T> TrackerMessage for T where T: Send + 'static {} | ||
|
||
pub trait TrackerMessageReceiver<Message: TrackerMessage>: | ||
Sink<Message, Error = mpsc::SendError> + Unpin + Send + Clone + 'static | ||
{ | ||
} | ||
|
||
impl<Message: TrackerMessage, T> TrackerMessageReceiver<Message> for T where | ||
T: Sink<Message, Error = mpsc::SendError> | ||
+ Unpin | ||
+ Send | ||
+ Clone | ||
+ 'static | ||
{ | ||
} | ||
} | ||
|
||
#[cfg(target_arch = "wasm32")] | ||
mod trait_aliases { | ||
use super::*; | ||
|
||
pub trait TrackerMessage: 'static {} | ||
|
||
impl<T> TrackerMessage for T where T: 'static {} | ||
|
||
pub trait TrackerMessageReceiver<Message: TrackerMessage>: | ||
Sink<Message, Error = mpsc::SendError> + Unpin + Clone + 'static | ||
{ | ||
} | ||
|
||
impl<Message: TrackerMessage, T> TrackerMessageReceiver<Message> for T where | ||
T: Sink<Message, Error = mpsc::SendError> + Unpin + Clone + 'static | ||
{ | ||
} | ||
} | ||
|
||
pub use trait_aliases::{TrackerMessage, TrackerMessageReceiver}; |
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.
Are these necessary? iced_web
is able to use the Runtime
and, therefore, the Tracker
already.
Lines 170 to 175 in 8a2a7f7
let mut runtime = iced_futures::Runtime::new( | |
Self::Executor::new().expect("Create executor"), | |
sender.clone(), | |
); | |
let (app, command) = runtime.enter(|| Self::new(flags)); |
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.
Sadly yes, this is necessary - we use winit
here with WebGL backend and it (winit) does not implement Send
on its EventLoopProxy
on wsam32, so yea, because of that we should lift here requirement for Send
for our types too
native/src/subscription.rs
Outdated
#[cfg(not(target_arch = "wasm32"))] | ||
type BoxStream<'a, T> = iced_futures::futures::stream::BoxStream<'a, T>; | ||
|
||
#[cfg(target_arch = "wasm32")] | ||
type BoxStream<'a, T> = iced_futures::futures::stream::LocalBoxStream<'a, T>; |
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.
These are already defined in iced_futures
!
Lines 43 to 69 in 8a2a7f7
/// A boxed static future. | |
/// | |
/// - On native platforms, it needs a `Send` requirement. | |
/// - On the Web platform, it does not need a `Send` requirement. | |
#[cfg(not(target_arch = "wasm32"))] | |
pub type BoxFuture<T> = futures::future::BoxFuture<'static, T>; | |
/// A boxed static future. | |
/// | |
/// - On native platforms, it needs a `Send` requirement. | |
/// - On the Web platform, it does not need a `Send` requirement. | |
#[cfg(target_arch = "wasm32")] | |
pub type BoxFuture<T> = futures::future::LocalBoxFuture<'static, T>; | |
/// A boxed static stream. | |
/// | |
/// - On native platforms, it needs a `Send` requirement. | |
/// - On the Web platform, it does not need a `Send` requirement. | |
#[cfg(not(target_arch = "wasm32"))] | |
pub type BoxStream<T> = futures::stream::BoxStream<'static, T>; | |
/// A boxed static stream. | |
/// | |
/// - On native platforms, it needs a `Send` requirement. | |
/// - On the Web platform, it does not need a `Send` requirement. | |
#[cfg(target_arch = "wasm32")] | |
pub type BoxStream<T> = futures::stream::LocalBoxStream<'static, T>; |
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.
fixed
Did you test input with this branch yet? I seem to have a bunch of issues but they are probably caused by winit. See this bug report here: rust-windowing/winit#2036 Problem is that iced still uses a custom winit branch, so it's hard to figure out what's going on is fixed upstream or not. |
@kaimast Ah... I see... Sliders in the example were working fine then I just tried to add cc @hecrj |
Could you rebase this on current master? iced has moved to wgpu 0.12 and it would be good to see if some of the issues are resolved. |
@kaimast sure, I'll try to find som spare time on this week and do the rebase |
env_logger::init(); | ||
|
||
// Initialize winit | ||
let event_loop = EventLoop::new(); | ||
|
||
#[cfg(target_arch = "wasm32")] | ||
let window = winit::window::WindowBuilder::new() |
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.
i think you can to save some cfg
by doing:
let window = if cfg!(target_arch = "wasm32") {
let canvas_element = {
console_log::init_with_level(log::Level::Debug)
.expect("could not initialize logger");
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
web_sys::window()
.and_then(|win| win.document())
.and_then(|doc| doc.get_element_by_id("iced_canvas"))
.and_then(|element| element.dyn_into::<HtmlCanvasElement>().ok())
.expect("Canvas with id `iced_canvas` is missing")
};
let window = winit::window::WindowBuilder::new()
.with_canvas(Some(canvas_element))
.build(&event_loop)
.expect("Failed to build winit window")
} else {
env_logger::init();
winit::window::Window::new(&event_loop).unwrap()
};
unless the Window::new()
method returns separate types
this is very interesting. does this patch allow to run in pure wgpu, without to use html elements for the widget? |
yes |
Wow this is great news! To experiment with targetting webgpu, will this approach here block in future to do this? Do we need to add a webgpu feature when/if we try such a thing? |
e6ab610
to
8b0f2e6
Compare
@kaimast Welp, I rebased the branch to the latest master (although, some parts of the code not polished yet and need refactoring), however the problems are still here - both input handling and text rendering issues on Firefox are still present. Unfortunately, I am currently have no time to research this further, If someone still interested in this feature, you are welcome to get this branch and continue work on it |
I created a tiny pull request that should fix the input issues. I think it should be close to being merge-able now. |
Thanks, @kaimast, merged |
winit/src/application.rs
Outdated
@@ -179,7 +178,7 @@ where | |||
|
|||
let mut context = task::Context::from_waker(task::noop_waker_ref()); | |||
|
|||
event_loop.run_return(move |event, _, control_flow| { | |||
event_loop.run(move |event, _, control_flow| { |
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.
@hecrj do you think this would break anything? It simplifies the code a lot and the winit
docs says about run_return
"You are strongly encouraged to use run, unless the use of this is absolutely necessary."
- Added missing `draw_cache_align_4x4` call for `brush_glyph` on wasm32 target - Added WebGL support to `integratio_wgpu` example - Fixed test.yml CI workflow - Removed spir-v shader in `integration_wgpu`; Fixed formatting - Removed redundant `BoxStream` typedef
... and hide the dependency under a `time` module in `iced_native`
It allows to clean up all the `trait_aliases` modules!
I made some changes here! Will explain everything first thing tomorrow! |
You can use `trunk serve` to easily compile them!
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.
Okay! First of all, thanks for all the efforts here. This is very cool!
As I mentioned yesterday, I made a bunch of changes, some of them quite important.
First, I have removed the iced_web
subcrate completely from the repository in 825c774! iced_web
has always been quite experimental and their dependencies have been outdated for a while now. Therefore, I believe it's better to move it to a different repository in the iced-rs
organization. As a consequence, from now on when targetting Wasm, iced
will leverage wgpu
and / or glow
to render into a canvas
using the iced_native
crate (see 26d95fd).
In my opinion, this is a better default than iced_web
because it makes targetting Wasm quite easier for users. As there are fewer differences between the native stack and the web stack, all of the native widgets should work on Wasm. If you have a native iced
application, chances are you can compile it to Wasm! No additional feature flags necessary! Just slap a --target wasm32-unknown-unknown
to your cargo build
command.
That said, the plan is to still offer iced_web
as a separate crate for users that need to leverage the DOM.
The rest of the changes are relatively minor:
- I changed the
Compositor
iniced_wgpu
to properly use WebGL limits in 7767241. - I created a new
time
module that offers a cross-platformInstant
implementation in 87b3e03 and 83c649b. - I introduced a
MaybeSend
trait iniced_futures
in 5dab5a3, which allows us to get rid of all thetrait_aliases
modules. - I have split the
iced_futures
executor implementations into differentbackend
modules in 167be45. Eachbackend
should expose the same API! - I implemented
time::every
for thewasm_bindgen
backend in e730d97.
Finally, I have added a couple of index.html
files to the todos
and tour
examples. You can try running them on your browser with trunk
.
There are still some issues present related to rendering text. My MacBook Pro M1 displays completely mangled text in all of the examples both in Chrome and Firefox:
This seems to happen only to dynamic text, which seems to indicate there may be an issue in the cache upload logic in wgpu_glyph
. Most likely related to hecrj/wgpu_glyph#78.
That said, I am pretty happy with the changes here and I think we can merge this! 🎉 We can iron out the issues in future PRs.
this is... awesome 😹 |
Made changes to allow the use of WebGL wgpu backend. The basic functionality works, but text rendering is still buggy - Somehow, if the initial value of the text control was changed, some parts of the text start to disappear/show artifacts.
UPD: Strange issue with text rendering is only reproducing in Firefox (v93). It is not directly related to the iced, I created an issue in
wgpu_glyph
here: hecrj/wgpu_glyph#78The current implementation provides neither
Application
norSandbox
implementations for this backend, and does not implement properClipboard
iniced_winit
, however, this should be at least some starting point.Changes list:
integration_wgpu_webgl
example, based onintegration_wgpu
andwgpu
'shello-triangle
example (can't useintegration_wgpu
example directly because it fails with its spirv shaders on WebGL)Sync
requirement forRuntime
andTracker
iniced_futures
webgl
feature toiced_wgpu
which enableswgpu/webgl
Clipboard
iniced_winit
Images
iced running inside WebGL canvas:
Text issues after changing text value:
Same example running on desktop backend: