Introduce Pipeline trait in wgpu::primitive

Co-authored-by: roguetechh <roguedotllc@gmail.com>
This commit is contained in:
Héctor Ramón Jiménez 2025-11-25 09:36:25 +01:00
parent a4829306cb
commit e937bf2bac
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
5 changed files with 61 additions and 44 deletions

View file

@ -128,16 +128,7 @@ impl Primitive {
}
impl shader::Primitive for Primitive {
type Renderer = Pipeline;
fn initialize(
&self,
device: &wgpu::Device,
queue: &wgpu::Queue,
format: wgpu::TextureFormat,
) -> Pipeline {
Pipeline::new(device, queue, format)
}
type Pipeline = Pipeline;
fn prepare(
&self,
@ -183,3 +174,13 @@ fn rnd_origin() -> Vec3 {
rand::thread_rng().gen_range(-4.0..2.0),
)
}
impl shader::Pipeline for Pipeline {
fn new(
device: &wgpu::Device,
queue: &wgpu::Queue,
format: wgpu::TextureFormat,
) -> Pipeline {
Self::new(device, queue, format)
}
}

View file

@ -66,4 +66,13 @@ impl Engine {
&self._shell,
)
}
pub fn trim(&mut self) {
self.text_pipeline.trim();
self.primitive_storage
.write()
.expect("primitive storage should be writable")
.trim();
}
}

View file

@ -149,8 +149,8 @@ impl Renderer {
self.triangle.trim();
self.text.trim();
// TODO: Move to runtime!
self.engine.text_pipeline.trim();
// TODO: Provide window id (?)
self.engine.trim();
#[cfg(any(feature = "svg", feature = "image"))]
{

View file

@ -19,23 +19,12 @@ pub trait Primitive: Debug + MaybeSend + MaybeSync + 'static {
///
/// 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,
) -> Self::Renderer;
type Pipeline: Pipeline + MaybeSend + MaybeSync;
/// Processes the [`Primitive`], allowing for GPU buffer allocation.
fn prepare(
&self,
renderer: &mut Self::Renderer,
pipeline: &mut Self::Pipeline,
device: &wgpu::Device,
queue: &wgpu::Queue,
bounds: &Rectangle,
@ -57,7 +46,7 @@ pub trait Primitive: Debug + MaybeSend + MaybeSync + 'static {
/// By default, it does nothing and returns `false`.
fn draw(
&self,
_renderer: &Self::Renderer,
_pipeline: &Self::Pipeline,
_render_pass: &mut wgpu::RenderPass<'_>,
) -> bool {
false
@ -70,7 +59,7 @@ pub trait Primitive: Debug + MaybeSend + MaybeSync + 'static {
/// By default, it does nothing.
fn render(
&self,
_renderer: &Self::Renderer,
_pipeline: &Self::Pipeline,
_encoder: &mut wgpu::CommandEncoder,
_target: &wgpu::TextureView,
_clip_bounds: &Rectangle<u32>,
@ -78,6 +67,26 @@ pub trait Primitive: Debug + MaybeSend + MaybeSync + 'static {
}
}
/// The pipeline of a graphics [`Primitive`].
pub trait Pipeline: Any + MaybeSend + MaybeSync {
/// Creates the [`Pipeline`] of a [`Primitive`].
///
/// This will only be called once, when the first [`Primitive`] with this kind
/// of [`Pipeline`] is encountered.
fn new(
device: &wgpu::Device,
queue: &wgpu::Queue,
format: wgpu::TextureFormat,
) -> Self
where
Self: Sized;
/// Trims any cached data in the [`Pipeline`].
///
/// This will normally be called at the end of a frame.
fn trim(&mut self) {}
}
pub(crate) trait Stored:
Debug + MaybeSend + MaybeSync + 'static
{
@ -122,15 +131,13 @@ impl<P: Primitive> Stored for BlackBox<P> {
viewport: &Viewport,
) {
if !storage.has::<P>() {
storage.store::<P, _>(
self.primitive.initialize(device, queue, format),
);
storage.store::<P, _>(P::Pipeline::new(device, queue, format));
}
let renderer = storage
.get_mut::<P>()
.expect("renderer should be initialized")
.downcast_mut::<P::Renderer>()
.downcast_mut::<P::Pipeline>()
.expect("renderer should have the proper type");
self.primitive
@ -145,7 +152,7 @@ impl<P: Primitive> Stored for BlackBox<P> {
let renderer = storage
.get::<P>()
.expect("renderer should be initialized")
.downcast_ref::<P::Renderer>()
.downcast_ref::<P::Pipeline>()
.expect("renderer should have the proper type");
self.primitive.draw(renderer, render_pass)
@ -161,7 +168,7 @@ impl<P: Primitive> Stored for BlackBox<P> {
let renderer = storage
.get::<P>()
.expect("renderer should be initialized")
.downcast_ref::<P::Renderer>()
.downcast_ref::<P::Pipeline>()
.expect("renderer should have the proper type");
self.primitive
@ -198,7 +205,7 @@ pub trait Renderer: core::Renderer {
/// Stores custom, user-provided types.
#[derive(Default)]
pub struct Storage {
pipelines: FxHashMap<TypeId, Box<dyn AnyConcurrent>>,
pipelines: FxHashMap<TypeId, Box<dyn Pipeline>>,
}
impl Storage {
@ -208,11 +215,8 @@ impl Storage {
}
/// Inserts the data `T` in to [`Storage`].
pub fn store<T: 'static, D: Any + MaybeSend + MaybeSync>(
&mut self,
data: D,
) {
let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(data));
pub fn store<T: 'static, P: Pipeline>(&mut self, pipeline: P) {
let _ = self.pipelines.insert(TypeId::of::<T>(), Box::new(pipeline));
}
/// Returns a reference to the data with type `T` if it exists in [`Storage`].
@ -228,8 +232,11 @@ impl Storage {
.get_mut(&TypeId::of::<T>())
.map(|pipeline| pipeline.as_mut() as &mut dyn Any)
}
/// Trims the cache of all the pipelines in the [`Storage`].
pub fn trim(&mut self) {
for pipeline in self.pipelines.values_mut() {
pipeline.trim();
}
}
}
trait AnyConcurrent: Any + MaybeSend + MaybeSync {}
impl<T> AnyConcurrent for T where T: Any + MaybeSend + MaybeSync {}

View file

@ -16,7 +16,7 @@ use std::marker::PhantomData;
pub use crate::Action;
pub use crate::graphics::Viewport;
pub use primitive::{Primitive, Storage};
pub use primitive::{Pipeline, Primitive, Storage};
/// A widget which can render custom shaders with Iced's `wgpu` backend.
///