diff --git a/examples/custom_shader/src/scene.rs b/examples/custom_shader/src/scene.rs index 5fa42188..88f72970 100644 --- a/examples/custom_shader/src/scene.rs +++ b/examples/custom_shader/src/scene.rs @@ -128,26 +128,25 @@ impl Primitive { } impl shader::Primitive for Primitive { - fn prepare( + type Renderer = Pipeline; + + fn initialize( &self, device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat, - storage: &mut shader::Storage, + ) -> Pipeline { + Pipeline::new(device, queue, format) + } + + fn prepare( + &self, + pipeline: &mut Pipeline, + device: &wgpu::Device, + queue: &wgpu::Queue, _bounds: &Rectangle, viewport: &Viewport, ) { - if !storage.has::() { - storage.store(Pipeline::new( - device, - queue, - format, - viewport.physical_size(), - )); - } - - let pipeline = storage.get_mut::().unwrap(); - // Upload data to GPU pipeline.update( device, @@ -161,14 +160,11 @@ impl shader::Primitive for Primitive { fn render( &self, + pipeline: &Pipeline, encoder: &mut wgpu::CommandEncoder, - storage: &shader::Storage, target: &wgpu::TextureView, clip_bounds: &Rectangle, ) { - // At this point our pipeline should always be initialized - let pipeline = storage.get::().unwrap(); - // Render primitive pipeline.render( target, diff --git a/examples/custom_shader/src/scene/pipeline.rs b/examples/custom_shader/src/scene/pipeline.rs index 7140bcaa..e15587e3 100644 --- a/examples/custom_shader/src/scene/pipeline.rs +++ b/examples/custom_shader/src/scene/pipeline.rs @@ -32,7 +32,6 @@ impl Pipeline { device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat, - target_size: Size, ) -> Self { //vertices of one cube let vertices = @@ -62,8 +61,8 @@ impl Pipeline { let depth_texture = device.create_texture(&wgpu::TextureDescriptor { label: Some("cubes depth texture"), size: wgpu::Extent3d { - width: target_size.width, - height: target_size.height, + width: 1, + height: 1, depth_or_array_layers: 1, }, mip_level_count: 1, @@ -297,7 +296,7 @@ impl Pipeline { uniforms, uniform_bind_group, vertices, - depth_texture_size: target_size, + depth_texture_size: Size::new(1, 1), depth_view, depth_pipeline, } diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index cd3a7de7..5ddb8461 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -235,13 +235,13 @@ impl Layer { pub fn draw_primitive( &mut self, bounds: Rectangle, - primitive: Box, + primitive: impl Primitive, transformation: Transformation, ) { let bounds = bounds * transformation; self.primitives - .push(primitive::Instance { bounds, primitive }); + .push(primitive::Instance::new(bounds, primitive)); } fn flush_meshes(&mut self) { diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index e55ad9a4..0ff74524 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -365,10 +365,10 @@ impl Renderer { for instance in &layer.primitives { instance.primitive.prepare( + &mut primitive_storage, &self.engine.device, &self.engine.queue, self.engine.format, - &mut primitive_storage, &instance.bounds, viewport, ); @@ -548,8 +548,8 @@ impl Renderer { .and_then(Rectangle::snap) { instance.primitive.render( - encoder, &primitive_storage, + encoder, frame, &clip_bounds, ); @@ -805,7 +805,7 @@ impl graphics::geometry::Renderer for Renderer { impl primitive::Renderer for Renderer { fn draw_primitive(&mut self, bounds: Rectangle, primitive: impl Primitive) { let (layer, transformation) = self.layers.current_mut(); - layer.draw_primitive(bounds, Box::new(primitive), transformation); + layer.draw_primitive(bounds, primitive, transformation); } } diff --git a/wgpu/src/primitive.rs b/wgpu/src/primitive.rs index dd877d4d..eef7cfe9 100644 --- a/wgpu/src/primitive.rs +++ b/wgpu/src/primitive.rs @@ -12,13 +12,32 @@ pub type Batch = Vec; /// A set of methods which allows a [`Primitive`] to be rendered. pub trait Primitive: Debug + MaybeSend + MaybeSync + 'static { - /// Processes the [`Primitive`], allowing for GPU buffer allocation. - fn prepare( + /// The shared renderer of this [`Primitive`]. + /// + /// Normally, this will contain a bunch of [`wgpu`] state; like + /// a rendering pipeline, buffers, and textures. + /// + /// All instances of this [`Primitive`] type will share the same + /// [`Renderer`]. + type Renderer: MaybeSend + MaybeSync; + + /// Initializes the [`Renderer`](Self::Renderer) of the [`Primitive`]. + /// + /// This will only be called once, when the first [`Primitive`] of this kind + /// is encountered. + fn initialize( &self, device: &wgpu::Device, queue: &wgpu::Queue, format: wgpu::TextureFormat, - storage: &mut Storage, + ) -> Self::Renderer; + + /// Processes the [`Primitive`], allowing for GPU buffer allocation. + fn prepare( + &self, + renderer: &mut Self::Renderer, + device: &wgpu::Device, + queue: &wgpu::Queue, bounds: &Rectangle, viewport: &Viewport, ); @@ -26,21 +45,92 @@ pub trait Primitive: Debug + MaybeSend + MaybeSync + 'static { /// Renders the [`Primitive`]. fn render( &self, + renderer: &Self::Renderer, encoder: &mut wgpu::CommandEncoder, + target: &wgpu::TextureView, + clip_bounds: &Rectangle, + ); +} + +pub(crate) trait Stored: + Debug + MaybeSend + MaybeSync + 'static +{ + fn prepare( + &self, + storage: &mut Storage, + device: &wgpu::Device, + queue: &wgpu::Queue, + format: wgpu::TextureFormat, + bounds: &Rectangle, + viewport: &Viewport, + ); + + fn render( + &self, storage: &Storage, + encoder: &mut wgpu::CommandEncoder, target: &wgpu::TextureView, clip_bounds: &Rectangle, ); } +#[derive(Debug)] +struct BlackBox { + primitive: P, +} + +impl Stored for BlackBox

{ + fn prepare( + &self, + storage: &mut Storage, + device: &wgpu::Device, + queue: &wgpu::Queue, + format: wgpu::TextureFormat, + bounds: &Rectangle, + viewport: &Viewport, + ) { + if !storage.has::

() { + storage.store::( + self.primitive.initialize(device, queue, format), + ); + } + + let renderer = storage + .get_mut::

() + .expect("renderer should be initialized") + .downcast_mut::() + .expect("renderer should have the proper type"); + + self.primitive + .prepare(renderer, device, queue, bounds, viewport); + } + + fn render( + &self, + storage: &Storage, + encoder: &mut wgpu::CommandEncoder, + target: &wgpu::TextureView, + clip_bounds: &Rectangle, + ) { + let renderer = storage + .get::

() + .expect("renderer should be initialized") + .downcast_ref::() + .expect("renderer should have the proper type"); + + self.primitive + .render(renderer, encoder, target, clip_bounds); + } +} + #[derive(Debug)] /// An instance of a specific [`Primitive`]. pub struct Instance { /// The bounds of the [`Instance`]. - pub bounds: Rectangle, + pub(crate) bounds: Rectangle, /// The [`Primitive`] to render. - pub primitive: Box, + pub(crate) primitive: Box, } impl Instance { @@ -48,7 +138,7 @@ impl Instance { pub fn new(bounds: Rectangle, primitive: impl Primitive) -> Self { Instance { bounds, - primitive: Box::new(primitive), + primitive: Box::new(BlackBox { primitive }), } } } @@ -73,26 +163,25 @@ impl Storage { } /// Inserts the data `T` in to [`Storage`]. - pub fn store(&mut self, data: T) { + pub fn store( + &mut self, + data: D, + ) { let _ = self.pipelines.insert(TypeId::of::(), Box::new(data)); } /// Returns a reference to the data with type `T` if it exists in [`Storage`]. - pub fn get(&self) -> Option<&T> { - self.pipelines.get(&TypeId::of::()).map(|pipeline| { - (pipeline.as_ref() as &dyn Any) - .downcast_ref::() - .expect("Value with this type does not exist in Storage.") - }) + pub fn get(&self) -> Option<&dyn Any> { + self.pipelines + .get(&TypeId::of::()) + .map(|pipeline| pipeline.as_ref() as &dyn Any) } /// Returns a mutable reference to the data with type `T` if it exists in [`Storage`]. - pub fn get_mut(&mut self) -> Option<&mut T> { - self.pipelines.get_mut(&TypeId::of::()).map(|pipeline| { - (pipeline.as_mut() as &mut dyn Any) - .downcast_mut::() - .expect("Value with this type does not exist in Storage.") - }) + pub fn get_mut(&mut self) -> Option<&mut dyn Any> { + self.pipelines + .get_mut(&TypeId::of::()) + .map(|pipeline| pipeline.as_mut() as &mut dyn Any) } }