summaryrefslogtreecommitdiffstats
path: root/examples/integration_wgpu
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-08-13 20:01:28 +0700
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2021-08-13 20:12:07 +0700
commit77a0b68aa176782e95048795aec15c20a3e60ec6 (patch)
treee4e7c2a34995a91b99a657539f92c8637f52c513 /examples/integration_wgpu
parenta646b11109aa451614d3fdf688e600aa48b87a56 (diff)
downloadiced-77a0b68aa176782e95048795aec15c20a3e60ec6.tar.gz
iced-77a0b68aa176782e95048795aec15c20a3e60ec6.tar.bz2
iced-77a0b68aa176782e95048795aec15c20a3e60ec6.zip
Rename `integration` examples
Diffstat (limited to 'examples/integration_wgpu')
-rw-r--r--examples/integration_wgpu/Cargo.toml11
-rw-r--r--examples/integration_wgpu/README.md20
-rw-r--r--examples/integration_wgpu/src/controls.rs110
-rw-r--r--examples/integration_wgpu/src/main.rs239
-rw-r--r--examples/integration_wgpu/src/scene.rs99
-rw-r--r--examples/integration_wgpu/src/shader/frag.spvbin0 -> 352 bytes
-rw-r--r--examples/integration_wgpu/src/shader/vert.spvbin0 -> 904 bytes
7 files changed, 479 insertions, 0 deletions
diff --git a/examples/integration_wgpu/Cargo.toml b/examples/integration_wgpu/Cargo.toml
new file mode 100644
index 00000000..743c655e
--- /dev/null
+++ b/examples/integration_wgpu/Cargo.toml
@@ -0,0 +1,11 @@
+[package]
+name = "integration_wgpu"
+version = "0.1.0"
+authors = ["Héctor Ramón Jiménez <hector0193@gmail.com>"]
+edition = "2018"
+publish = false
+
+[dependencies]
+iced_winit = { path = "../../winit" }
+iced_wgpu = { path = "../../wgpu" }
+env_logger = "0.8"
diff --git a/examples/integration_wgpu/README.md b/examples/integration_wgpu/README.md
new file mode 100644
index 00000000..53ffd3e5
--- /dev/null
+++ b/examples/integration_wgpu/README.md
@@ -0,0 +1,20 @@
+## `wgpu` integration
+
+A demonstration of how to integrate Iced in an existing graphical application
+that leverages [`wgpu`].
+
+The __[`main`]__ file contains all the code of the example.
+
+<div align="center">
+ <a href="https://gfycat.com/nicemediocrekodiakbear">
+ <img src="https://thumbs.gfycat.com/NiceMediocreKodiakbear-small.gif">
+ </a>
+</div>
+
+You can run it with `cargo run`:
+```
+cargo run --package integration
+```
+
+[`main`]: src/main.rs
+[`wgpu`]: https://github.com/gfx-rs/wgpu
diff --git a/examples/integration_wgpu/src/controls.rs b/examples/integration_wgpu/src/controls.rs
new file mode 100644
index 00000000..36ee9b7e
--- /dev/null
+++ b/examples/integration_wgpu/src/controls.rs
@@ -0,0 +1,110 @@
+use iced_wgpu::Renderer;
+use iced_winit::{
+ slider, Align, Clipboard, Color, Column, Command, Element, Length, Program,
+ Row, Slider, Text,
+};
+
+pub struct Controls {
+ background_color: Color,
+ sliders: [slider::State; 3],
+}
+
+#[derive(Debug, Clone)]
+pub enum Message {
+ BackgroundColorChanged(Color),
+}
+
+impl Controls {
+ pub fn new() -> Controls {
+ Controls {
+ background_color: Color::BLACK,
+ sliders: Default::default(),
+ }
+ }
+
+ pub fn background_color(&self) -> Color {
+ self.background_color
+ }
+}
+
+impl Program for Controls {
+ type Renderer = Renderer;
+ type Message = Message;
+ type Clipboard = Clipboard;
+
+ fn update(
+ &mut self,
+ message: Message,
+ _clipboard: &mut Clipboard,
+ ) -> Command<Message> {
+ match message {
+ Message::BackgroundColorChanged(color) => {
+ self.background_color = color;
+ }
+ }
+
+ Command::none()
+ }
+
+ fn view(&mut self) -> Element<Message, Renderer> {
+ let [r, g, b] = &mut self.sliders;
+ let background_color = self.background_color;
+
+ let sliders = Row::new()
+ .width(Length::Units(500))
+ .spacing(20)
+ .push(
+ Slider::new(r, 0.0..=1.0, background_color.r, move |r| {
+ Message::BackgroundColorChanged(Color {
+ r,
+ ..background_color
+ })
+ })
+ .step(0.01),
+ )
+ .push(
+ Slider::new(g, 0.0..=1.0, background_color.g, move |g| {
+ Message::BackgroundColorChanged(Color {
+ g,
+ ..background_color
+ })
+ })
+ .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)
+ .height(Length::Fill)
+ .align_items(Align::End)
+ .push(
+ Column::new()
+ .width(Length::Fill)
+ .align_items(Align::End)
+ .push(
+ Column::new()
+ .padding(10)
+ .spacing(10)
+ .push(
+ Text::new("Background color")
+ .color(Color::WHITE),
+ )
+ .push(sliders)
+ .push(
+ Text::new(format!("{:?}", background_color))
+ .size(14)
+ .color(Color::WHITE),
+ ),
+ ),
+ )
+ .into()
+ }
+}
diff --git a/examples/integration_wgpu/src/main.rs b/examples/integration_wgpu/src/main.rs
new file mode 100644
index 00000000..6f319466
--- /dev/null
+++ b/examples/integration_wgpu/src/main.rs
@@ -0,0 +1,239 @@
+mod controls;
+mod scene;
+
+use controls::Controls;
+use scene::Scene;
+
+use iced_wgpu::{wgpu, Backend, Renderer, Settings, Viewport};
+use iced_winit::{conversion, futures, program, winit, Clipboard, Debug, Size};
+
+use futures::task::SpawnExt;
+use winit::{
+ dpi::PhysicalPosition,
+ event::{Event, ModifiersState, WindowEvent},
+ event_loop::{ControlFlow, EventLoop},
+};
+
+pub fn main() {
+ env_logger::init();
+
+ // Initialize winit
+ let event_loop = EventLoop::new();
+ let window = winit::window::Window::new(&event_loop).unwrap();
+
+ 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();
+ let mut clipboard = Clipboard::connect(&window);
+
+ // Initialize wgpu
+ let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
+ let surface = unsafe { instance.create_surface(&window) };
+
+ let (format, (mut device, queue)) = futures::executor::block_on(async {
+ let adapter = instance
+ .request_adapter(&wgpu::RequestAdapterOptions {
+ power_preference: wgpu::PowerPreference::HighPerformance,
+ compatible_surface: Some(&surface),
+ })
+ .await
+ .expect("Request adapter");
+
+ (
+ adapter
+ .get_swap_chain_preferred_format(&surface)
+ .expect("Get preferred format"),
+ adapter
+ .request_device(
+ &wgpu::DeviceDescriptor {
+ label: None,
+ features: wgpu::Features::empty(),
+ limits: wgpu::Limits::default(),
+ },
+ None,
+ )
+ .await
+ .expect("Request device"),
+ )
+ });
+
+ let mut swap_chain = {
+ let size = window.inner_size();
+
+ device.create_swap_chain(
+ &surface,
+ &wgpu::SwapChainDescriptor {
+ usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
+ format,
+ width: size.width,
+ height: size.height,
+ present_mode: wgpu::PresentMode::Mailbox,
+ },
+ )
+ };
+ let mut resized = false;
+
+ // 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 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(), format));
+
+ 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| {
+ // You should change this if you want to render continuosly
+ *control_flow = ControlFlow::Wait;
+
+ match event {
+ Event::WindowEvent { event, .. } => {
+ match event {
+ WindowEvent::CursorMoved { position, .. } => {
+ cursor_position = position;
+ }
+ WindowEvent::ModifiersChanged(new_modifiers) => {
+ modifiers = new_modifiers;
+ }
+ WindowEvent::Resized(new_size) => {
+ viewport = Viewport::with_physical_size(
+ Size::new(new_size.width, new_size.height),
+ window.scale_factor(),
+ );
+
+ resized = true;
+ }
+ WindowEvent::CloseRequested => {
+ *control_flow = ControlFlow::Exit;
+ }
+ _ => {}
+ }
+
+ // Map window event to iced event
+ if let Some(event) = iced_winit::conversion::window_event(
+ &event,
+ window.scale_factor(),
+ modifiers,
+ ) {
+ state.queue_event(event);
+ }
+ }
+ Event::MainEventsCleared => {
+ // 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(),
+ ),
+ &mut renderer,
+ &mut clipboard,
+ &mut debug,
+ );
+
+ // and request a redraw
+ window.request_redraw();
+ }
+ }
+ Event::RedrawRequested(_) => {
+ if resized {
+ let size = window.inner_size();
+
+ swap_chain = device.create_swap_chain(
+ &surface,
+ &wgpu::SwapChainDescriptor {
+ usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
+ format: format,
+ width: size.width,
+ height: size.height,
+ present_mode: wgpu::PresentMode::Mailbox,
+ },
+ );
+
+ resized = false;
+ }
+
+ match swap_chain.get_current_frame() {
+ Ok(frame) => {
+ let mut encoder = device.create_command_encoder(
+ &wgpu::CommandEncoderDescriptor { label: None },
+ );
+
+ 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.backend_mut().draw(
+ &mut device,
+ &mut staging_belt,
+ &mut encoder,
+ &frame.output.view,
+ &viewport,
+ state.primitive(),
+ &debug.overlay(),
+ );
+
+ // Then we submit the work
+ staging_belt.finish();
+ queue.submit(Some(encoder.finish()));
+
+ // 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();
+ }
+ Err(error) => match error {
+ wgpu::SwapChainError::OutOfMemory => {
+ panic!("Swapchain error: {}. Rendering cannot continue.", error)
+ }
+ _ => {
+ // Try rendering again next frame.
+ window.request_redraw();
+ }
+ },
+ }
+ }
+ _ => {}
+ }
+ })
+}
diff --git a/examples/integration_wgpu/src/scene.rs b/examples/integration_wgpu/src/scene.rs
new file mode 100644
index 00000000..3e8277c8
--- /dev/null
+++ b/examples/integration_wgpu/src/scene.rs
@@ -0,0 +1,99 @@
+use iced_wgpu::wgpu;
+use iced_winit::Color;
+
+pub struct Scene {
+ pipeline: wgpu::RenderPipeline,
+}
+
+impl Scene {
+ pub fn new(device: &wgpu::Device) -> Scene {
+ let pipeline = build_pipeline(device);
+
+ Scene { pipeline }
+ }
+
+ pub fn clear<'a>(
+ &self,
+ target: &'a wgpu::TextureView,
+ encoder: &'a mut wgpu::CommandEncoder,
+ background_color: Color,
+ ) -> wgpu::RenderPass<'a> {
+ encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+ label: None,
+ color_attachments: &[wgpu::RenderPassColorAttachment {
+ view: 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,
+ }
+ }),
+ store: true,
+ },
+ }],
+ depth_stencil_attachment: None,
+ })
+ }
+
+ 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 {
+ let vs_module =
+ device.create_shader_module(&wgpu::include_spirv!("shader/vert.spv"));
+
+ let fs_module =
+ device.create_shader_module(&wgpu::include_spirv!("shader/frag.spv"));
+
+ let pipeline_layout =
+ device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
+ label: None,
+ push_constant_ranges: &[],
+ bind_group_layouts: &[],
+ });
+
+ let pipeline =
+ device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
+ label: None,
+ layout: Some(&pipeline_layout),
+ vertex: wgpu::VertexState {
+ module: &vs_module,
+ entry_point: "main",
+ buffers: &[],
+ },
+ fragment: Some(wgpu::FragmentState {
+ module: &fs_module,
+ entry_point: "main",
+ targets: &[wgpu::ColorTargetState {
+ format: wgpu::TextureFormat::Bgra8UnormSrgb,
+ blend: Some(wgpu::BlendState {
+ color: wgpu::BlendComponent::REPLACE,
+ alpha: wgpu::BlendComponent::REPLACE,
+ }),
+ write_mask: wgpu::ColorWrite::ALL,
+ }],
+ }),
+ primitive: wgpu::PrimitiveState {
+ topology: wgpu::PrimitiveTopology::TriangleList,
+ front_face: wgpu::FrontFace::Ccw,
+ ..Default::default()
+ },
+ depth_stencil: None,
+ multisample: wgpu::MultisampleState {
+ count: 1,
+ mask: !0,
+ alpha_to_coverage_enabled: false,
+ },
+ });
+
+ pipeline
+}
diff --git a/examples/integration_wgpu/src/shader/frag.spv b/examples/integration_wgpu/src/shader/frag.spv
new file mode 100644
index 00000000..9d6807c9
--- /dev/null
+++ b/examples/integration_wgpu/src/shader/frag.spv
Binary files differ
diff --git a/examples/integration_wgpu/src/shader/vert.spv b/examples/integration_wgpu/src/shader/vert.spv
new file mode 100644
index 00000000..0cabc9c0
--- /dev/null
+++ b/examples/integration_wgpu/src/shader/vert.spv
Binary files differ