summaryrefslogtreecommitdiffstats
path: root/examples/integration
diff options
context:
space:
mode:
Diffstat (limited to 'examples/integration')
-rw-r--r--examples/integration/Cargo.toml2
-rw-r--r--examples/integration/src/controls.rs64
-rw-r--r--examples/integration/src/main.rs233
-rw-r--r--examples/integration/src/scene.rs109
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
}