diff options
Diffstat (limited to 'examples/integration')
-rw-r--r-- | examples/integration/Cargo.toml | 2 | ||||
-rw-r--r-- | examples/integration/src/controls.rs | 64 | ||||
-rw-r--r-- | examples/integration/src/main.rs | 233 | ||||
-rw-r--r-- | examples/integration/src/scene.rs | 109 |
4 files changed, 198 insertions, 210 deletions
diff --git a/examples/integration/Cargo.toml b/examples/integration/Cargo.toml index afc2c791..4515502f 100644 --- a/examples/integration/Cargo.toml +++ b/examples/integration/Cargo.toml @@ -8,4 +8,4 @@ publish = false [dependencies] iced_winit = { path = "../../winit" } iced_wgpu = { path = "../../wgpu" } -env_logger = "0.7" +env_logger = "0.8" diff --git a/examples/integration/src/controls.rs b/examples/integration/src/controls.rs index 0999336b..824f9f53 100644 --- a/examples/integration/src/controls.rs +++ b/examples/integration/src/controls.rs @@ -1,15 +1,15 @@ -use crate::Scene; - use iced_wgpu::Renderer; use iced_winit::{ - slider, Align, Color, Column, Element, Length, Row, Slider, Text, + slider, Align, Color, Column, Command, Element, Length, Program, Row, + Slider, Text, }; pub struct Controls { + background_color: Color, sliders: [slider::State; 3], } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Message { BackgroundColorChanged(Color), } @@ -17,58 +17,64 @@ pub enum Message { impl Controls { pub fn new() -> Controls { Controls { + background_color: Color::BLACK, sliders: Default::default(), } } - pub fn update(&self, message: Message, scene: &mut Scene) { + pub fn background_color(&self) -> Color { + self.background_color + } +} + +impl Program for Controls { + type Renderer = Renderer; + type Message = Message; + + fn update(&mut self, message: Message) -> Command<Message> { match message { Message::BackgroundColorChanged(color) => { - scene.background_color = color; + self.background_color = color; } } + + Command::none() } - pub fn view(&mut self, scene: &Scene) -> Element<Message, Renderer> { + fn view(&mut self) -> Element<Message, Renderer> { let [r, g, b] = &mut self.sliders; - let background_color = scene.background_color; + let background_color = self.background_color; let sliders = Row::new() .width(Length::Units(500)) .spacing(20) - .push(Slider::new( - r, - 0.0..=1.0, - scene.background_color.r, - move |r| { + .push( + Slider::new(r, 0.0..=1.0, background_color.r, move |r| { Message::BackgroundColorChanged(Color { r, ..background_color }) - }, - )) - .push(Slider::new( - g, - 0.0..=1.0, - scene.background_color.g, - move |g| { + }) + .step(0.01), + ) + .push( + Slider::new(g, 0.0..=1.0, background_color.g, move |g| { Message::BackgroundColorChanged(Color { g, ..background_color }) - }, - )) - .push(Slider::new( - b, - 0.0..=1.0, - scene.background_color.b, - move |b| { + }) + .step(0.01), + ) + .push( + Slider::new(b, 0.0..=1.0, background_color.b, move |b| { Message::BackgroundColorChanged(Color { b, ..background_color }) - }, - )); + }) + .step(0.01), + ); Row::new() .width(Length::Fill) diff --git a/examples/integration/src/main.rs b/examples/integration/src/main.rs index 92d2fa8d..9b52f3a5 100644 --- a/examples/integration/src/main.rs +++ b/examples/integration/src/main.rs @@ -4,14 +4,12 @@ mod scene; use controls::Controls; use scene::Scene; -use iced_wgpu::{ - wgpu, window::SwapChain, Primitive, Renderer, Settings, Target, -}; -use iced_winit::{ - futures, mouse, winit, Cache, Clipboard, Size, UserInterface, -}; +use iced_wgpu::{wgpu, Backend, Renderer, Settings, Viewport}; +use iced_winit::{conversion, futures, program, winit, Debug, Size}; +use futures::task::SpawnExt; use winit::{ + dpi::PhysicalPosition, event::{Event, ModifiersState, WindowEvent}, event_loop::{ControlFlow, EventLoop}, }; @@ -22,32 +20,39 @@ pub fn main() { // Initialize winit let event_loop = EventLoop::new(); let window = winit::window::Window::new(&event_loop).unwrap(); - let mut logical_size = - window.inner_size().to_logical(window.scale_factor()); + + let physical_size = window.inner_size(); + let mut viewport = Viewport::with_physical_size( + Size::new(physical_size.width, physical_size.height), + window.scale_factor(), + ); + let mut cursor_position = PhysicalPosition::new(-1.0, -1.0); let mut modifiers = ModifiersState::default(); - // Initialize WGPU + // Initialize wgpu + let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); + let surface = unsafe { instance.create_surface(&window) }; - let surface = wgpu::Surface::create(&window); let (mut device, queue) = futures::executor::block_on(async { - let adapter = wgpu::Adapter::request( - &wgpu::RequestAdapterOptions { + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::Default, compatible_surface: Some(&surface), - }, - wgpu::BackendBit::PRIMARY, - ) - .await - .expect("Request adapter"); + }) + .await + .expect("Request adapter"); adapter - .request_device(&wgpu::DeviceDescriptor { - extensions: wgpu::Extensions { - anisotropic_filtering: false, + .request_device( + &wgpu::DeviceDescriptor { + features: wgpu::Features::empty(), + limits: wgpu::Limits::default(), + shader_validation: false, }, - limits: wgpu::Limits::default(), - }) + None, + ) .await + .expect("Request device") }); let format = wgpu::TextureFormat::Bgra8UnormSrgb; @@ -55,20 +60,39 @@ pub fn main() { let mut swap_chain = { let size = window.inner_size(); - SwapChain::new(&device, &surface, format, size.width, size.height) + device.create_swap_chain( + &surface, + &wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Mailbox, + }, + ) }; let mut resized = false; - // Initialize iced - let mut events = Vec::new(); - let mut cache = Some(Cache::default()); - let mut renderer = Renderer::new(&mut device, Settings::default()); - let mut output = (Primitive::None, mouse::Interaction::default()); - let clipboard = Clipboard::new(&window); + // Initialize staging belt and local pool + let mut staging_belt = wgpu::util::StagingBelt::new(5 * 1024); + let mut local_pool = futures::executor::LocalPool::new(); // Initialize scene and GUI controls - let mut scene = Scene::new(&device); - let mut controls = Controls::new(); + let scene = Scene::new(&mut device); + let controls = Controls::new(); + + // Initialize iced + let mut debug = Debug::new(); + let mut renderer = + Renderer::new(Backend::new(&mut device, Settings::default())); + + let mut state = program::State::new( + controls, + viewport.logical_size(), + conversion::cursor_position(cursor_position, viewport.scale_factor()), + &mut renderer, + &mut debug, + ); // Run event loop event_loop.run(move |event, _, control_flow| { @@ -78,18 +102,23 @@ pub fn main() { match event { Event::WindowEvent { event, .. } => { match event { + WindowEvent::CursorMoved { position, .. } => { + cursor_position = position; + } WindowEvent::ModifiersChanged(new_modifiers) => { modifiers = new_modifiers; } WindowEvent::Resized(new_size) => { - logical_size = - new_size.to_logical(window.scale_factor()); + viewport = Viewport::with_physical_size( + Size::new(new_size.width, new_size.height), + window.scale_factor(), + ); + resized = true; } WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; } - _ => {} } @@ -99,117 +128,95 @@ pub fn main() { window.scale_factor(), modifiers, ) { - events.push(event); + state.queue_event(event); } } Event::MainEventsCleared => { - // If no relevant events happened, we can simply skip this - if events.is_empty() { - return; - } - - // We need to: - // 1. Process events of our user interface. - // 2. Update state as a result of any interaction. - // 3. Generate a new output for our renderer. - - // First, we build our user interface. - let mut user_interface = UserInterface::build( - controls.view(&scene), - Size::new(logical_size.width, logical_size.height), - cache.take().unwrap(), - &mut renderer, - ); - - // Then, we process the events, obtaining messages in return. - let messages = user_interface.update( - events.drain(..), - clipboard.as_ref().map(|c| c as _), - &renderer, - ); - - let user_interface = if messages.is_empty() { - // If there are no messages, no interactions we care about have - // happened. We can simply leave our user interface as it is. - user_interface - } else { - // If there are messages, we need to update our state - // accordingly and rebuild our user interface. - // We can only do this if we drop our user interface first - // by turning it into its cache. - cache = Some(user_interface.into_cache()); - - // In this example, `Controls` is the only part that cares - // about messages, so updating our state is pretty - // straightforward. - for message in messages { - controls.update(message, &mut scene); - } - - // Once the state has been changed, we rebuild our updated - // user interface. - UserInterface::build( - controls.view(&scene), - Size::new(logical_size.width, logical_size.height), - cache.take().unwrap(), + // If there are events pending + if !state.is_queue_empty() { + // We update iced + let _ = state.update( + viewport.logical_size(), + conversion::cursor_position( + cursor_position, + viewport.scale_factor(), + ), + None, &mut renderer, - ) - }; - - // Finally, we just need to draw a new output for our renderer, - output = user_interface.draw(&mut renderer); - - // update our cache, - cache = Some(user_interface.into_cache()); + &mut debug, + ); - // and request a redraw - window.request_redraw(); + // and request a redraw + window.request_redraw(); + } } Event::RedrawRequested(_) => { if resized { let size = window.inner_size(); - swap_chain = SwapChain::new( - &device, + swap_chain = device.create_swap_chain( &surface, - format, - size.width, - size.height, + &wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: format, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Mailbox, + }, ); + + resized = false; } - let (frame, viewport) = - swap_chain.next_frame().expect("Next frame"); + let frame = swap_chain.get_current_frame().expect("Next frame"); let mut encoder = device.create_command_encoder( &wgpu::CommandEncoderDescriptor { label: None }, ); - // We draw the scene first - scene.draw(&mut encoder, &frame.view); + let program = state.program(); + + { + // We clear the frame + let mut render_pass = scene.clear( + &frame.output.view, + &mut encoder, + program.background_color(), + ); + + // Draw the scene + scene.draw(&mut render_pass); + } // And then iced on top - let mouse_interaction = renderer.draw( + let mouse_interaction = renderer.backend_mut().draw( &mut device, + &mut staging_belt, &mut encoder, - Target { - texture: &frame.view, - viewport, - }, - &output, - window.scale_factor(), - &["Some debug information!"], + &frame.output.view, + &viewport, + state.primitive(), + &debug.overlay(), ); // Then we submit the work - queue.submit(&[encoder.finish()]); + staging_belt.finish(); + queue.submit(Some(encoder.finish())); - // And update the mouse cursor + // Update the mouse cursor window.set_cursor_icon( iced_winit::conversion::mouse_interaction( mouse_interaction, ), ); + + // And recall staging buffers + local_pool + .spawner() + .spawn(staging_belt.recall()) + .expect("Recall staging buffers"); + + local_pool.run_until_stalled(); } _ => {} } diff --git a/examples/integration/src/scene.rs b/examples/integration/src/scene.rs index 22c6812a..03a338c6 100644 --- a/examples/integration/src/scene.rs +++ b/examples/integration/src/scene.rs @@ -2,91 +2,68 @@ use iced_wgpu::wgpu; use iced_winit::Color; pub struct Scene { - pub background_color: Color, pipeline: wgpu::RenderPipeline, - bind_group: wgpu::BindGroup, } impl Scene { pub fn new(device: &wgpu::Device) -> Scene { - let (pipeline, bind_group) = build_pipeline(device); + let pipeline = build_pipeline(device); - Scene { - background_color: Color::BLACK, - pipeline, - bind_group, - } + Scene { pipeline } } - pub fn draw( + pub fn clear<'a>( &self, - encoder: &mut wgpu::CommandEncoder, - target: &wgpu::TextureView, - ) { - let mut rpass = - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[ - wgpu::RenderPassColorAttachmentDescriptor { - attachment: target, - resolve_target: None, - load_op: wgpu::LoadOp::Clear, - store_op: wgpu::StoreOp::Store, - clear_color: { - let [r, g, b, a] = - self.background_color.into_linear(); + target: &'a wgpu::TextureView, + encoder: &'a mut wgpu::CommandEncoder, + background_color: Color, + ) -> wgpu::RenderPass<'a> { + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: target, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear({ + let [r, g, b, a] = background_color.into_linear(); - wgpu::Color { - r: r as f64, - g: g as f64, - b: b as f64, - a: a as f64, - } - }, - }, - ], - depth_stencil_attachment: None, - }); + wgpu::Color { + r: r as f64, + g: g as f64, + b: b as f64, + a: a as f64, + } + }), + store: true, + }, + }], + depth_stencil_attachment: None, + }) + } - rpass.set_pipeline(&self.pipeline); - rpass.set_bind_group(0, &self.bind_group, &[]); - rpass.draw(0..3, 0..1); + pub fn draw<'a>(&'a self, render_pass: &mut wgpu::RenderPass<'a>) { + render_pass.set_pipeline(&self.pipeline); + render_pass.draw(0..3, 0..1); } } -fn build_pipeline( - device: &wgpu::Device, -) -> (wgpu::RenderPipeline, wgpu::BindGroup) { - let vs = include_bytes!("shader/vert.spv"); - let fs = include_bytes!("shader/frag.spv"); - - let vs_module = device.create_shader_module( - &wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap(), - ); +fn build_pipeline(device: &wgpu::Device) -> wgpu::RenderPipeline { + let vs_module = + device.create_shader_module(wgpu::include_spirv!("shader/vert.spv")); - let fs_module = device.create_shader_module( - &wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap(), - ); - - let bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - label: None, - bindings: &[], - }); - - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - label: None, - layout: &bind_group_layout, - bindings: &[], - }); + let fs_module = + device.create_shader_module(wgpu::include_spirv!("shader/frag.spv")); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout], + label: None, + push_constant_ranges: &[], + bind_group_layouts: &[], }); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - layout: &pipeline_layout, + label: None, + layout: Some(&pipeline_layout), vertex_stage: wgpu::ProgrammableStageDescriptor { module: &vs_module, entry_point: "main", @@ -98,9 +75,7 @@ fn build_pipeline( rasterization_state: Some(wgpu::RasterizationStateDescriptor { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::None, - depth_bias: 0, - depth_bias_slope_scale: 0.0, - depth_bias_clamp: 0.0, + ..Default::default() }), primitive_topology: wgpu::PrimitiveTopology::TriangleList, color_states: &[wgpu::ColorStateDescriptor { @@ -119,5 +94,5 @@ fn build_pipeline( alpha_to_coverage_enabled: false, }); - (pipeline, bind_group) + pipeline } |