lambda/render/
pipeline.rs

1//! Render pipeline builders and definitions for lambda runtimes and
2//! applications.
3use std::rc::Rc;
4
5use lambda_platform::gfx::shader::{
6  ShaderModuleBuilder,
7  ShaderModuleType,
8};
9
10use super::{
11  buffer::Buffer,
12  internal::RenderBackend,
13  shader::Shader,
14  RenderContext,
15};
16
17#[derive(Debug)]
18pub struct RenderPipeline {
19  pipeline: Rc<
20    lambda_platform::gfx::pipeline::RenderPipeline<
21      super::internal::RenderBackend,
22    >,
23  >,
24  buffers: Vec<Rc<Buffer>>,
25}
26
27impl RenderPipeline {
28  /// Destroy the render pipeline with the render context that created it.
29  pub fn destroy(self, render_context: &RenderContext) {
30    logging::trace!("Destroying render pipeline");
31    Rc::try_unwrap(self.pipeline)
32      .expect("Failed to destroy render pipeline")
33      .destroy(render_context.internal_gpu());
34
35    logging::trace!("Destroying buffers");
36    for buffer in self.buffers {
37      Rc::try_unwrap(buffer)
38        .expect("Failed to get high level buffer.")
39        .destroy(render_context);
40    }
41
42    logging::info!("Render pipeline & all attached buffers destroyed");
43  }
44}
45
46impl RenderPipeline {
47  pub(super) fn buffers(&self) -> &Vec<Rc<Buffer>> {
48    return &self.buffers;
49  }
50
51  pub(super) fn into_platform_render_pipeline(
52    &self,
53  ) -> Rc<lambda_platform::gfx::pipeline::RenderPipeline<RenderBackend>> {
54    return self.pipeline.clone();
55  }
56}
57
58use lambda_platform::gfx::pipeline::PushConstantUpload;
59pub use lambda_platform::gfx::{
60  assembler::VertexAttribute,
61  pipeline::PipelineStage,
62};
63
64pub struct RenderPipelineBuilder {
65  push_constants: Vec<PushConstantUpload>,
66  buffers: Vec<Rc<Buffer>>,
67  attributes: Vec<VertexAttribute>,
68}
69
70impl RenderPipelineBuilder {
71  /// Creates a new render pipeline builder.
72  pub fn new() -> Self {
73    return Self {
74      push_constants: Vec::new(),
75      buffers: Vec::new(),
76      attributes: Vec::new(),
77    };
78  }
79
80  /// Adds a buffer to the render pipeline.
81  pub fn with_buffer(
82    mut self,
83    buffer: Buffer,
84    attributes: Vec<VertexAttribute>,
85  ) -> Self {
86    self.buffers.push(Rc::new(buffer));
87    self.attributes.extend(attributes);
88    return self;
89  }
90
91  /// Adds a push constant to the render pipeline at the given stage
92  /// with the given size in bytes.
93  pub fn with_push_constant(
94    mut self,
95    stage: PipelineStage,
96    bytes: u32,
97  ) -> Self {
98    self.push_constants.push((stage, 0..bytes));
99    return self;
100  }
101
102  /// Builds a render pipeline based on your builder configuration.
103  pub fn build(
104    self,
105    render_context: &mut RenderContext,
106    render_pass: &super::render_pass::RenderPass,
107    vertex_shader: &Shader,
108    fragment_shader: Option<&Shader>,
109  ) -> RenderPipeline {
110    logging::debug!("Building render pipeline");
111
112    logging::debug!("Building vertex shader... ");
113    let vertex_shader_module = ShaderModuleBuilder::new().build(
114      render_context.internal_mutable_gpu(),
115      &vertex_shader.as_binary(),
116      ShaderModuleType::Vertex,
117    );
118
119    logging::debug!(
120      "\tDone. (Vertex shader: {} bytes)",
121      vertex_shader.as_binary().len()
122    );
123
124    logging::debug!("Building fragment shader... ");
125    let fragment_shader_module = match fragment_shader {
126      Some(shader) => Some(ShaderModuleBuilder::new().build(
127        render_context.internal_mutable_gpu(),
128        &shader.as_binary(),
129        ShaderModuleType::Fragment,
130      )),
131      None => None,
132    };
133
134    logging::debug!(
135      "\tDone. (Fragment shader: {} bytes)",
136      fragment_shader.map(|s| s.as_binary().len()).unwrap_or(0)
137    );
138
139    let builder = lambda_platform::gfx::pipeline::RenderPipelineBuilder::new();
140
141    let buffers = self.buffers;
142    let internal_buffers = buffers
143      .iter()
144      .map(|b| b.internal_buffer())
145      .collect::<Vec<_>>();
146
147    let render_pipeline = builder
148      .with_push_constants(self.push_constants.clone())
149      .build(
150        render_context.internal_gpu(),
151        render_pass.internal_render_pass(),
152        &vertex_shader_module,
153        fragment_shader_module.as_ref(),
154        &internal_buffers,
155        self.attributes.as_slice(),
156      );
157
158    // Clean up shader modules.
159    vertex_shader_module.destroy(render_context.internal_mutable_gpu());
160    if let Some(fragment_shader_module) = fragment_shader_module {
161      fragment_shader_module.destroy(render_context.internal_mutable_gpu());
162    }
163
164    return RenderPipeline {
165      pipeline: Rc::new(render_pipeline),
166      buffers,
167    };
168  }
169}