Skip to content

Commit

Permalink
Re-organize custom module as pipeline module
Browse files Browse the repository at this point in the history
... and move `Shader` widget to `iced_widget` crate
  • Loading branch information
hecrj committed Nov 14, 2023
1 parent 2dda913 commit 9489e29
Show file tree
Hide file tree
Showing 14 changed files with 246 additions and 197 deletions.
11 changes: 8 additions & 3 deletions examples/custom_shader/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ mod cubes;
mod pipeline;
mod primitive;

use crate::camera::Camera;
use crate::cubes::Cubes;
use crate::pipeline::Pipeline;

use iced::executor;
use iced::time::Instant;
use iced::widget::{
checkbox, column, container, row, slider, text, vertical_space, Shader,
};
use iced::window;
use iced::{
executor, window, Alignment, Application, Color, Command, Element, Length,
Renderer, Subscription, Theme,
Alignment, Application, Color, Command, Element, Length, Renderer,
Subscription, Theme,
};
use std::time::Instant;

fn main() -> iced::Result {
IcedCubes::run(iced::Settings::default())
Expand Down
15 changes: 8 additions & 7 deletions examples/custom_shader/src/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ pub mod vertex;
mod buffer;
mod uniforms;

use crate::camera::Camera;
use crate::pipeline::Pipeline;
use crate::primitive::cube::Cube;
pub use buffer::Buffer;
pub use cube::Cube;
pub use uniforms::Uniforms;
pub use vertex::Vertex;

use crate::Camera;
use crate::Pipeline;

use iced::advanced::graphics::Transformation;
use iced::widget::shader;
use iced::{Color, Rectangle, Size};

pub use crate::primitive::vertex::Vertex;
pub use buffer::Buffer;
pub use uniforms::Uniforms;

/// A collection of `Cube`s that can be rendered.
#[derive(Debug)]
pub struct Primitive {
Expand Down
44 changes: 23 additions & 21 deletions renderer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
#![forbid(rust_2018_idioms)]
#![deny(unsafe_code, unused_results, rustdoc::broken_intra_doc_links)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(feature = "wgpu")]
pub use iced_wgpu as wgpu;

pub mod compositor;

#[cfg(feature = "geometry")]
pub mod geometry;

mod settings;
pub mod widget;

pub use iced_graphics as graphics;
pub use iced_graphics::core;
Expand Down Expand Up @@ -60,26 +62,6 @@ impl<T> Renderer<T> {
}
}
}

pub fn draw_custom<P: widget::shader::Primitive>(
&mut self,
bounds: Rectangle,
primitive: P,
) {
match self {
Renderer::TinySkia(_) => {
log::warn!(
"Custom shader primitive is unavailable with tiny-skia."
);
}
#[cfg(feature = "wgpu")]
Renderer::Wgpu(renderer) => {
renderer.draw_primitive(iced_wgpu::Primitive::Custom(
iced_wgpu::primitive::Custom::shader(bounds, primitive),
));
}
}
}
}

impl<T> core::Renderer for Renderer<T> {
Expand Down Expand Up @@ -292,3 +274,23 @@ impl<T> crate::graphics::geometry::Renderer for Renderer<T> {
}
}
}

#[cfg(feature = "wgpu")]
impl<T> iced_wgpu::primitive::pipeline::Renderer for Renderer<T> {
fn draw_pipeline_primitive(
&mut self,
bounds: Rectangle,
primitive: impl wgpu::primitive::pipeline::Primitive,
) {
match self {
Self::TinySkia(_renderer) => {
log::warn!(
"Custom shader primitive is unavailable with tiny-skia."
);
}
Self::Wgpu(renderer) => {
renderer.draw_pipeline_primitive(bounds, primitive);
}
}
}
}
2 changes: 0 additions & 2 deletions renderer/src/widget.rs

This file was deleted.

29 changes: 15 additions & 14 deletions wgpu/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use crate::core::{Color, Size};
use crate::graphics::backend;
use crate::graphics::color;
use crate::graphics::{Transformation, Viewport};
use crate::primitive::pipeline;
use crate::primitive::{self, Primitive};
use crate::{custom, quad, text, triangle};
use crate::quad;
use crate::text;
use crate::triangle;
use crate::{Layer, Settings};

#[cfg(feature = "tracing")]
Expand All @@ -23,7 +26,7 @@ pub struct Backend {
quad_pipeline: quad::Pipeline,
text_pipeline: text::Pipeline,
triangle_pipeline: triangle::Pipeline,
pipeline_storage: custom::Storage,
pipeline_storage: pipeline::Storage,

#[cfg(any(feature = "image", feature = "svg"))]
image_pipeline: image::Pipeline,
Expand All @@ -49,7 +52,7 @@ impl Backend {
quad_pipeline,
text_pipeline,
triangle_pipeline,
pipeline_storage: custom::Storage::default(),
pipeline_storage: pipeline::Storage::default(),

#[cfg(any(feature = "image", feature = "svg"))]
image_pipeline,
Expand Down Expand Up @@ -183,9 +186,9 @@ impl Backend {
);
}

if !layer.shaders.is_empty() {
for shader in &layer.shaders {
shader.primitive.prepare(
if !layer.pipelines.is_empty() {
for pipeline in &layer.pipelines {
pipeline.primitive.prepare(
format,
device,
queue,
Expand Down Expand Up @@ -323,19 +326,17 @@ impl Backend {
// kill render pass to let custom shaders get mut access to encoder
let _ = ManuallyDrop::into_inner(render_pass);

if !layer.shaders.is_empty() {
for shader in &layer.shaders {
//This extra check is needed since each custom pipeline must set it's own
//scissor rect, which will panic if bounds.w/h < 1
let bounds = shader.bounds * scale_factor;
if !layer.pipelines.is_empty() {
for pipeline in &layer.pipelines {
let bounds = (pipeline.bounds * scale_factor).snap();

if bounds.width < 1.0 || bounds.height < 1.0 {
if bounds.width < 1 || bounds.height < 1 {
continue;
}

shader.primitive.render(
pipeline.primitive.render(
&self.pipeline_storage,
bounds.snap(),
bounds,
target,
target_size,
encoder,
Expand Down
63 changes: 2 additions & 61 deletions wgpu/src/custom.rs
Original file line number Diff line number Diff line change
@@ -1,67 +1,8 @@
//! Draw custom primitives.
use crate::core::{Rectangle, Size};
use crate::graphics::Transformation;
use crate::primitive;

use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt::Debug;

/// Stores custom, user-provided pipelines.
#[derive(Default, Debug)]
pub struct Storage {
pipelines: HashMap<TypeId, Box<dyn Any>>,
}

impl Storage {
/// Returns `true` if `Storage` contains a pipeline with type `T`.
pub fn has<T: 'static>(&self) -> bool {
self.pipelines.get(&TypeId::of::<T>()).is_some()
}

/// Inserts the pipeline `T` in to [`Storage`].
pub fn store<T: 'static>(&mut self, pipeline: T) {
let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
}

/// Returns a reference to pipeline with type `T` if it exists in [`Storage`].
pub fn get<T: 'static>(&self) -> Option<&T> {
self.pipelines.get(&TypeId::of::<T>()).map(|pipeline| {
pipeline
.downcast_ref::<T>()
.expect("Pipeline with this type does not exist in Storage.")
})
}

/// Returns a mutable reference to pipeline `T` if it exists in [`Storage`].
pub fn get_mut<T: 'static>(&mut self) -> Option<&mut T> {
self.pipelines.get_mut(&TypeId::of::<T>()).map(|pipeline| {
pipeline
.downcast_mut::<T>()
.expect("Pipeline with this type does not exist in Storage.")
})
}
}

/// A set of methods which allows a [`Primitive`] to be rendered.
pub trait Primitive: Debug + Send + Sync + 'static {
/// Processes the [`Primitive`], allowing for GPU buffer allocation.
fn prepare(
&self,
format: wgpu::TextureFormat,
device: &wgpu::Device,
queue: &wgpu::Queue,
target_size: Size<u32>,
scale_factor: f32,
transform: Transformation,
storage: &mut Storage,
);

/// Renders the [`Primitive`].
fn render(
&self,
storage: &Storage,
bounds: Rectangle<u32>,
target: &wgpu::TextureView,
target_size: Size<u32>,
encoder: &mut wgpu::CommandEncoder,
);
}
19 changes: 12 additions & 7 deletions wgpu/src/layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ pub struct Layer<'a> {
/// The images of the [`Layer`].
pub images: Vec<Image>,

/// The custom shader primitives of this [`Layer`].
pub shaders: Vec<primitive::Shader>,
/// The custom pipelines of this [`Layer`].
pub pipelines: Vec<primitive::Pipeline>,
}

impl<'a> Layer<'a> {
Expand All @@ -48,7 +48,7 @@ impl<'a> Layer<'a> {
meshes: Vec::new(),
text: Vec::new(),
images: Vec::new(),
shaders: Vec::new(),
pipelines: Vec::new(),
}
}

Expand Down Expand Up @@ -312,16 +312,21 @@ impl<'a> Layer<'a> {
}
}
},
primitive::Custom::Shader(shader) => {
primitive::Custom::Pipeline(pipeline) => {
let layer = &mut layers[current_layer];

let bounds = Rectangle::new(
Point::new(translation.x, translation.y),
shader.bounds.size(),
pipeline.bounds.size(),
);

if layer.bounds.intersection(&bounds).is_some() {
layer.shaders.push(shader.clone());
if let Some(clip_bounds) =
layer.bounds.intersection(&bounds)
{
layer.pipelines.push(primitive::Pipeline {
bounds: clip_bounds,
primitive: pipeline.primitive.clone(),
});
}
}
},
Expand Down
1 change: 0 additions & 1 deletion wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
rustdoc::broken_intra_doc_links
)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
pub mod custom;
pub mod layer;
pub mod primitive;
pub mod settings;
Expand Down
43 changes: 8 additions & 35 deletions wgpu/src/primitive.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//! Draw using different graphical primitives.
pub mod pipeline;

pub use pipeline::Pipeline;

use crate::core::Rectangle;
use crate::custom;
use crate::graphics::{Damage, Mesh};
use std::any::Any;

use std::fmt::Debug;
use std::sync::Arc;

/// The graphical primitives supported by `iced_wgpu`.
pub type Primitive = crate::graphics::Primitive<Custom>;
Expand All @@ -14,44 +16,15 @@ pub type Primitive = crate::graphics::Primitive<Custom>;
pub enum Custom {
/// A mesh primitive.
Mesh(Mesh),
/// A custom shader primitive
Shader(Shader),
}

impl Custom {
/// Create a custom [`Shader`] primitive.
pub fn shader<P: custom::Primitive>(
bounds: Rectangle,
primitive: P,
) -> Self {
Self::Shader(Shader {
bounds,
primitive: Arc::new(primitive),
})
}
/// A custom pipeline primitive.
Pipeline(Pipeline),
}

impl Damage for Custom {
fn bounds(&self) -> Rectangle {
match self {
Self::Mesh(mesh) => mesh.bounds(),
Self::Shader(shader) => shader.bounds,
Self::Pipeline(pipeline) => pipeline.bounds,
}
}
}

#[derive(Clone, Debug)]
/// A custom primitive which can be used to render primitives associated with a custom pipeline.
pub struct Shader {
/// The bounds of the [`Shader`].
pub bounds: Rectangle,

/// The [`custom::Primitive`] to render.
pub primitive: Arc<dyn custom::Primitive>,
}

impl PartialEq for Shader {
fn eq(&self, other: &Self) -> bool {
self.primitive.type_id() == other.primitive.type_id()
}
}
Loading

0 comments on commit 9489e29

Please sign in to comment.