taika/rendering/
mod.rs

1use std::{
2    rc::Rc,
3    sync::{Arc, Mutex},
4};
5
6use wgpu::{CommandEncoder, Device, Queue};
7
8use crate::window::TargetProperties;
9
10pub mod compute;
11pub mod drawable;
12mod primary_draw_pass;
13pub mod shader;
14pub mod vertex;
15pub use primary_draw_pass::PrimaryDrawPass;
16
17pub trait RenderPass {
18    fn render(
19        &mut self,
20        device: &Device,
21        encoder: &mut CommandEncoder,
22        queue: &Queue,
23        target: &wgpu::TextureView,
24        global_bind_group: &wgpu::BindGroup,
25        bind_group_layout: &wgpu::BindGroupLayout,
26        target_properties: &TargetProperties,
27    );
28
29    fn init(
30        &mut self,
31        device: &Device,
32        bind_group_layout: &wgpu::BindGroupLayout,
33        target_properties: &TargetProperties,
34    );
35}
36
37pub trait RenderPipeline {
38    fn render(
39        &mut self,
40        device: &Device,
41        encoder: &mut CommandEncoder,
42        queue: &Queue,
43        target: &wgpu::TextureView,
44        target_properties: &TargetProperties,
45    );
46
47    fn init(
48        &mut self,
49        device: &Device,
50        bind_group_layout: &wgpu::BindGroupLayout,
51        target_properties: &TargetProperties,
52    );
53}
54
55pub struct DefaultRenderPipeline {
56    render_passes: Vec<Arc<Mutex<dyn RenderPass>>>,
57    global_bind_group: Box<dyn GlobalBindGroup>,
58    initialized: bool,
59    #[allow(dead_code)]
60    name: String,
61}
62
63impl DefaultRenderPipeline {
64    pub fn new(global_bind_group: Box<dyn GlobalBindGroup>, name: &str) -> Self {
65        DefaultRenderPipeline {
66            render_passes: Vec::new(),
67            initialized: false,
68            global_bind_group,
69            name: name.to_string(),
70        }
71    }
72
73    pub fn add_render_pass(&mut self, render_pass: Arc<Mutex<dyn RenderPass>>) {
74        self.render_passes.push(render_pass);
75    }
76}
77
78impl RenderPipeline for DefaultRenderPipeline {
79    fn render(
80        &mut self,
81        device: &Device,
82        encoder: &mut CommandEncoder,
83        queue: &Queue,
84        target: &wgpu::TextureView,
85        target_properties: &TargetProperties,
86    ) {
87        if !self.initialized {
88            let bind_group_layout = self.global_bind_group.get_layout(device);
89            self.init(device, &bind_group_layout, target_properties);
90            self.initialized = true;
91        }
92        self.global_bind_group.pre_render(device, queue);
93        for render_pass in &mut self.render_passes {
94            render_pass.lock().unwrap().render(
95                device,
96                encoder,
97                queue,
98                target,
99                &self.global_bind_group.get_group(),
100                self.global_bind_group.get_layout(device).as_ref(),
101                target_properties,
102            )
103        }
104    }
105
106    fn init(
107        &mut self,
108        device: &Device,
109        bind_group_layout: &wgpu::BindGroupLayout,
110        target_properties: &TargetProperties,
111    ) {
112        self.global_bind_group.init(device);
113        for pass in self.render_passes.iter_mut() {
114            pass.lock()
115                .unwrap()
116                .init(device, bind_group_layout, target_properties);
117        }
118    }
119}
120
121/// A bind group that is applied render-pipeline wide
122pub trait GlobalBindGroup {
123    fn get_layout(&mut self, device: &wgpu::Device) -> Rc<wgpu::BindGroupLayout>;
124    fn init(&mut self, device: &wgpu::Device);
125    fn get_group(&mut self) -> Rc<wgpu::BindGroup>;
126    fn pre_render(&mut self, device: &wgpu::Device, queue: &wgpu::Queue);
127}