-
Notifications
You must be signed in to change notification settings - Fork 844
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
Update winit to 0.30 and refactor examples #5709
Draft
anima-libera
wants to merge
2
commits into
gfx-rs:trunk
Choose a base branch
from
anima-libera:update-winit-to-0.30
base: trunk
Could not load branches
Branch not found: {{ refName }}
Could not load tags
Nothing to show
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
+1,026
−638
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
If it worked it could fix #5214 |
The problem with
cwfitzgerald suggested that
|
Perhaps something like this for wasm use std::{borrow::Cow, sync::Arc};
use winit::{
application::ApplicationHandler,
event::WindowEvent,
event_loop::{ActiveEventLoop, EventLoop},
window::{Window, WindowId},
};
use crate::framework;
#[cfg(target_arch = "wasm32")]
use web_time as time;
#[cfg(target_arch = "wasm32")]
use std::cell::RefCell;
#[cfg(target_arch = "wasm32")]
use winit::event_loop::ControlFlow;
#[cfg(target_arch = "wasm32")]
const WAIT_TIME: time::Duration = time::Duration::from_millis(100);
#[cfg(target_arch = "wasm32")]
enum Message {
Initialized(InitializedLoopState),
}
#[cfg(target_arch = "wasm32")]
thread_local! {
pub static MESSAGE_QUEUE: RefCell<Vec<Message>> = RefCell::new(Vec::new());
}
struct LoopState {
// See https://docs.rs/winit/latest/winit/changelog/v0_30/index.html#removed
// for the recommended pratcice regarding Window creation (from which everything depends)
// in winit >= 0.30.0.
// The actual state is in an Option because its initialization is now delayed to after
// the even loop starts running.
state: Option<InitializedLoopState>
}
impl LoopState {
fn new() -> LoopState {
LoopState { state: None }
}
}
struct InitializedLoopState {
window: Arc<Window>,
_instance: wgpu::Instance,
surface: wgpu::Surface<'static>,
_adapter: wgpu::Adapter,
device: wgpu::Device,
queue: wgpu::Queue,
_shader: wgpu::ShaderModule,
_pipeline_layout: wgpu::PipelineLayout,
render_pipeline: wgpu::RenderPipeline,
config: wgpu::SurfaceConfiguration,
}
impl InitializedLoopState {
async fn new(window: Arc<Window>) -> InitializedLoopState {
let mut size = window.inner_size();
size.width = size.width.max(1);
size.height = size.height.max(1);
let instance = wgpu::Instance::default();
let surface = instance.create_surface(window.clone()).unwrap();
let adapter = wgpu::util::initialize_adapter_from_env_or_default(&instance, Some(&surface))
.await
.expect("Failed to find an appropriate adapter");
// Create the logical device and command queue
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::empty(),
// Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
.using_resolution(adapter.limits()),
},
None,
)
.await
.expect("Failed to create device");
// Load the shaders from disk
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let swapchain_capabilities = surface.get_capabilities(&adapter);
let swapchain_format = swapchain_capabilities.formats[0];
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
compilation_options: Default::default(),
targets: &[Some(swapchain_format.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
});
let config = surface
.get_default_config(&adapter, size.width, size.height)
.unwrap();
surface.configure(&device, &config);
InitializedLoopState {
window,
_instance: instance,
surface,
_adapter: adapter,
device,
queue,
_shader: shader,
_pipeline_layout: pipeline_layout,
render_pipeline,
config,
}
}
}
impl ApplicationHandler for LoopState {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if self.state.is_none() {
#[allow(unused_mut)]
let mut attributes = Window::default_attributes();
#[cfg(target_arch = "wasm32")]
{
log::info!("Creating canvas element for wasm32 target");
use wasm_bindgen::JsCast;
use winit::platform::web::WindowAttributesExtWebSys;
let canvas = web_sys::window()
.unwrap()
.document()
.unwrap()
.get_element_by_id("canvas")
.unwrap()
.dyn_into::<web_sys::HtmlCanvasElement>()
.unwrap();
attributes = attributes.with_canvas(Some(canvas));
}
// Move this into the state struct?
let window = Arc::new(event_loop.create_window(attributes).unwrap());
#[cfg(not(target_arch = "wasm32"))]
{
self.state = Some(pollster::block_on(InitializedLoopState::new(window)));
}
#[cfg(target_arch = "wasm32")]
{
wasm_bindgen_futures::spawn_local(async move {
let initialized_state = InitializedLoopState::new(window).await;
MESSAGE_QUEUE.with_borrow_mut(|queue| {
queue.push(Message::Initialized(initialized_state))
});
});
}
}
}
fn about_to_wait(&mut self, event_loop: &ActiveEventLoop) {
#[cfg(target_arch = "wasm32")]
{
MESSAGE_QUEUE.with_borrow_mut(|queue| {
for message in queue.drain(..) {
match message {
Message::Initialized(state) => {
self.state = Some(state);
}
}
}
});
event_loop.set_control_flow(ControlFlow::WaitUntil(time::Instant::now() + WAIT_TIME));
}
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
_window_id: WindowId,
event: WindowEvent,
) {
if let Some(state) = self.state.as_mut().as_mut() {
match event {
WindowEvent::Resized(new_size) => {
// Reconfigure the surface with the new size
state.config.width = new_size.width.max(1);
state.config.height = new_size.height.max(1);
state.surface.configure(&state.device, &state.config);
// On macos the window needs to be redrawn manually after resizing
state.window.request_redraw();
}
WindowEvent::RedrawRequested => {
let frame = state
.surface
.get_current_texture()
.expect("Failed to acquire next swap chain texture");
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = state
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
rpass.set_pipeline(&state.render_pipeline);
rpass.draw(0..3, 0..1);
}
state.queue.submit(Some(encoder.finish()));
frame.present();
}
WindowEvent::CloseRequested => event_loop.exit(),
_ => {}
}
}
}
}
pub fn main() {
framework::init_logger();
log::info!("Initializing...");
let mut loop_state = LoopState::new();
let event_loop = EventLoop::new().unwrap();
log::info!("Entering event loop...");
event_loop.run_app(&mut loop_state).unwrap();
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
Attempted to update winit to 0.30 and to refactor the examples accordingly. It does not work for the
wasm32
target (sorry, I had no idea what I was doing, trying to block in web browsers, not used to that); but for non-wasm32
targets it seems to work (to the extent that I could test) so it may be useful in the end.About the player crate, it is left untouched (so does not compile), but it can be ignored by changing this line into
(which may be a bad idea, since all the other dependencies seem in sync in the workspace) in order to focus on the examples or run xtask now.
There are 5 modules to partially refactor:
framework
hello_triangle
,hello_windows
anduniform_values
examples (they do not use theframework
to handle the creation of their window(s) and event loop)player
crateNote: I made the
hello_triangle
andhello_windows
examples let theWGPU_ADAPTER_NAME
env variable have a say in their choice of adapter (as the example framework does for all the examples that use it). (I did that to be able to run the examples that would no work with the default adapter on my machine, the issue there is most probably on my end and most probably not a concern.)Note: There were mysterious numbers in the
uniform_values
example that could be labels referenced from some documentation that I could not find, they are mostly still above what they were labeling but since the code have moved around it may require whatever is referencing these labels to be partially rewritten to not rot.Testing
This was tested on one machine (X11, Nvidia GPU) and works for the native target (some examples that use the framework were run, the three other examples were also run and they all seemed to work fine). Does not compile for
wasm32
. Even withplayer
's winit version set back down to 0.29 (to run xtask), xtask's output seems negative (and some part of that negativity is probably aboutwasm32
target not even compiling in theexample
crate, hard to tell).Checklist
cargo fmt
.cargo clippy
. If applicable, add:--target wasm32-unknown-unknown
--target wasm32-unknown-emscripten
cargo xtask test
to run tests.CHANGELOG.md
. See simple instructions inside file.