1use {
2 super::{RenderGroup, RenderGroupDesc},
3 crate::{
4 command::{QueueId, RenderPassEncoder},
5 factory::Factory,
6 graph::GraphContext,
7 node::{
8 render::PrepareResult, BufferAccess, DescBuilder, ImageAccess, NodeBuffer, NodeImage,
9 },
10 resource::{DescriptorSetLayout, Handle},
11 },
12 rendy_core::hal::{device::Device as _, Backend},
13};
14
15pub use crate::core::types::{Layout, SetLayout};
16
17#[derive(Clone, Debug)]
19pub struct Pipeline {
20 pub layout: Layout,
22
23 pub vertices: Vec<(
25 Vec<rendy_core::hal::pso::Element<rendy_core::hal::format::Format>>,
26 rendy_core::hal::pso::ElemStride,
27 rendy_core::hal::pso::VertexInputRate,
28 )>,
29
30 pub colors: Vec<rendy_core::hal::pso::ColorBlendDesc>,
32
33 pub depth_stencil: rendy_core::hal::pso::DepthStencilDesc,
35
36 pub rasterizer: rendy_core::hal::pso::Rasterizer,
38
39 pub input_assembler_desc: rendy_core::hal::pso::InputAssemblerDesc,
41}
42
43pub trait SimpleGraphicsPipelineDesc<B: Backend, T: ?Sized>: std::fmt::Debug {
45 type Pipeline: SimpleGraphicsPipeline<B, T>;
47
48 fn builder(self) -> DescBuilder<B, T, SimpleRenderGroupDesc<Self>>
50 where
51 Self: Sized,
52 {
53 SimpleRenderGroupDesc { inner: self }.builder()
54 }
55
56 fn buffers(&self) -> Vec<BufferAccess> {
58 Vec::new()
59 }
60
61 fn images(&self) -> Vec<ImageAccess> {
63 Vec::new()
64 }
65
66 fn colors(&self) -> Vec<rendy_core::hal::pso::ColorBlendDesc> {
68 vec![rendy_core::hal::pso::ColorBlendDesc {
69 mask: rendy_core::hal::pso::ColorMask::ALL,
70 blend: Some(rendy_core::hal::pso::BlendState::ALPHA),
71 }]
72 }
73
74 fn depth_stencil(&self) -> Option<rendy_core::hal::pso::DepthStencilDesc> {
76 Some(rendy_core::hal::pso::DepthStencilDesc {
77 depth: Some(rendy_core::hal::pso::DepthTest {
78 fun: rendy_core::hal::pso::Comparison::Less,
79 write: true,
80 }),
81 depth_bounds: false,
82 stencil: None,
83 })
84 }
85
86 fn rasterizer(&self) -> rendy_core::hal::pso::Rasterizer {
88 rendy_core::hal::pso::Rasterizer::FILL
89 }
90
91 fn vertices(
93 &self,
94 ) -> Vec<(
95 Vec<rendy_core::hal::pso::Element<rendy_core::hal::format::Format>>,
96 rendy_core::hal::pso::ElemStride,
97 rendy_core::hal::pso::VertexInputRate,
98 )> {
99 Vec::new()
100 }
101
102 fn layout(&self) -> Layout {
105 Layout {
106 sets: Vec::new(),
107 push_constants: Vec::new(),
108 }
109 }
110
111 fn input_assembler(&self) -> rendy_core::hal::pso::InputAssemblerDesc {
113 rendy_core::hal::pso::InputAssemblerDesc {
114 primitive: rendy_core::hal::pso::Primitive::TriangleList,
115 with_adjacency: false,
116 restart_index: None,
117 }
118 }
119
120 fn pipeline(&self) -> Pipeline {
122 Pipeline {
123 layout: self.layout(),
124 vertices: self.vertices(),
125 colors: self.colors(),
126 depth_stencil: self
127 .depth_stencil()
128 .unwrap_or(rendy_core::hal::pso::DepthStencilDesc::default()),
129 rasterizer: self.rasterizer(),
130 input_assembler_desc: self.input_assembler(),
131 }
132 }
133
134 fn load_shader_set(&self, factory: &mut Factory<B>, aux: &T) -> rendy_shader::ShaderSet<B>;
144
145 fn build<'a>(
147 self,
148 ctx: &GraphContext<B>,
149 factory: &mut Factory<B>,
150 queue: QueueId,
151 aux: &T,
152 buffers: Vec<NodeBuffer>,
153 images: Vec<NodeImage>,
154 set_layouts: &[Handle<DescriptorSetLayout<B>>],
155 ) -> Result<Self::Pipeline, rendy_core::hal::pso::CreationError>;
156}
157
158pub trait SimpleGraphicsPipeline<B: Backend, T: ?Sized>:
160 std::fmt::Debug + Sized + Send + Sync + 'static
161{
162 type Desc: SimpleGraphicsPipelineDesc<B, T, Pipeline = Self>;
164
165 fn builder() -> DescBuilder<B, T, SimpleRenderGroupDesc<Self::Desc>>
167 where
168 Self::Desc: Default,
169 {
170 Self::Desc::default().builder()
171 }
172
173 fn prepare(
177 &mut self,
178 _factory: &Factory<B>,
179 _queue: QueueId,
180 _set_layouts: &[Handle<DescriptorSetLayout<B>>],
181 _index: usize,
182 _aux: &T,
183 ) -> PrepareResult {
184 PrepareResult::DrawRecord
185 }
186
187 fn draw(
189 &mut self,
190 layout: &B::PipelineLayout,
191 encoder: RenderPassEncoder<'_, B>,
192 index: usize,
193 aux: &T,
194 );
195
196 fn dispose(self, factory: &mut Factory<B>, aux: &T);
198}
199
200#[derive(Debug)]
202pub struct SimpleRenderGroup<B: Backend, P> {
203 set_layouts: Vec<Handle<DescriptorSetLayout<B>>>,
204 pipeline_layout: B::PipelineLayout,
205 graphics_pipeline: B::GraphicsPipeline,
206 pipeline: P,
207}
208
209#[derive(Debug)]
211pub struct SimpleRenderGroupDesc<P: std::fmt::Debug> {
212 inner: P,
213}
214
215impl<B, T, P> RenderGroupDesc<B, T> for SimpleRenderGroupDesc<P>
216where
217 B: Backend,
218 T: ?Sized,
219 P: SimpleGraphicsPipelineDesc<B, T>,
220{
221 fn buffers(&self) -> Vec<BufferAccess> {
222 self.inner.buffers()
223 }
224
225 fn images(&self) -> Vec<ImageAccess> {
226 self.inner.images()
227 }
228
229 fn colors(&self) -> usize {
230 self.inner.colors().len()
231 }
232
233 fn depth(&self) -> bool {
234 self.inner.depth_stencil().is_some()
235 }
236
237 fn build<'a>(
238 self,
239 ctx: &GraphContext<B>,
240 factory: &mut Factory<B>,
241 queue: QueueId,
242 aux: &T,
243 framebuffer_width: u32,
244 framebuffer_height: u32,
245 subpass: rendy_core::hal::pass::Subpass<'_, B>,
246 buffers: Vec<NodeBuffer>,
247 images: Vec<NodeImage>,
248 ) -> Result<Box<dyn RenderGroup<B, T>>, rendy_core::hal::pso::CreationError> {
249 log::trace!("Load shader sets for");
250
251 let mut shader_set = self.inner.load_shader_set(factory, aux);
252
253 let pipeline = self.inner.pipeline();
254
255 let set_layouts = pipeline
256 .layout
257 .sets
258 .into_iter()
259 .map(|set| {
260 factory
261 .create_descriptor_set_layout(set.bindings)
262 .map(Handle::from)
263 })
264 .collect::<Result<Vec<_>, _>>()
265 .map_err(|e| {
266 shader_set.dispose(factory);
267 e
268 })?;
269
270 let pipeline_layout = unsafe {
271 factory.device().create_pipeline_layout(
272 set_layouts.iter().map(|l| l.raw()),
273 pipeline.layout.push_constants,
274 )
275 }
276 .map_err(|e| {
277 shader_set.dispose(factory);
278 rendy_core::hal::pso::CreationError::OutOfMemory(e)
279 })?;
280
281 assert_eq!(pipeline.colors.len(), self.inner.colors().len());
282
283 let mut vertex_buffers = Vec::new();
284 let mut attributes = Vec::new();
285
286 for &(ref elemets, stride, rate) in &pipeline.vertices {
287 push_vertex_desc(elemets, stride, rate, &mut vertex_buffers, &mut attributes);
288 }
289
290 let rect = rendy_core::hal::pso::Rect {
291 x: 0,
292 y: 0,
293 w: framebuffer_width as i16,
294 h: framebuffer_height as i16,
295 };
296
297 let shaders = match shader_set.raw() {
298 Err(e) => {
299 shader_set.dispose(factory);
300 log::warn!("Shader error {:?}", e);
301 return Err(rendy_core::hal::pso::CreationError::Other);
302 }
303 Ok(s) => s,
304 };
305
306 let graphics_pipeline = unsafe {
307 factory.device().create_graphics_pipelines(
308 Some(rendy_core::hal::pso::GraphicsPipelineDesc {
309 shaders,
310 rasterizer: pipeline.rasterizer,
311 vertex_buffers,
312 attributes,
313 input_assembler: pipeline.input_assembler_desc,
314 blender: rendy_core::hal::pso::BlendDesc {
315 logic_op: None,
316 targets: pipeline.colors.clone(),
317 },
318 depth_stencil: pipeline.depth_stencil,
319 multisampling: None,
320 baked_states: rendy_core::hal::pso::BakedStates {
321 viewport: Some(rendy_core::hal::pso::Viewport {
322 rect,
323 depth: 0.0..1.0,
324 }),
325 scissor: Some(rect),
326 blend_color: None,
327 depth_bounds: None,
328 },
329 layout: &pipeline_layout,
330 subpass,
331 flags: rendy_core::hal::pso::PipelineCreationFlags::empty(),
332 parent: rendy_core::hal::pso::BasePipeline::None,
333 }),
334 None,
335 )
336 }
337 .remove(0)
338 .map_err(|e| {
339 shader_set.dispose(factory);
340 e
341 })?;
342
343 let pipeline = self
344 .inner
345 .build(ctx, factory, queue, aux, buffers, images, &set_layouts)
346 .map_err(|e| {
347 shader_set.dispose(factory);
348 e
349 })?;
350
351 shader_set.dispose(factory);
352
353 Ok(Box::new(SimpleRenderGroup::<B, _> {
354 set_layouts,
355 pipeline_layout,
356 graphics_pipeline,
357 pipeline,
358 }))
359 }
360}
361
362impl<B, T, P> RenderGroup<B, T> for SimpleRenderGroup<B, P>
363where
364 B: Backend,
365 T: ?Sized,
366 P: SimpleGraphicsPipeline<B, T>,
367{
368 fn prepare(
369 &mut self,
370 factory: &Factory<B>,
371 queue: QueueId,
372 index: usize,
373 _subpass: rendy_core::hal::pass::Subpass<'_, B>,
374 aux: &T,
375 ) -> PrepareResult {
376 self.pipeline
377 .prepare(factory, queue, &self.set_layouts, index, aux)
378 }
379
380 fn draw_inline(
381 &mut self,
382 mut encoder: RenderPassEncoder<'_, B>,
383 index: usize,
384 _subpass: rendy_core::hal::pass::Subpass<'_, B>,
385 aux: &T,
386 ) {
387 encoder.bind_graphics_pipeline(&self.graphics_pipeline);
388 self.pipeline
389 .draw(&self.pipeline_layout, encoder, index, aux);
390 }
391
392 fn dispose(self: Box<Self>, factory: &mut Factory<B>, aux: &T) {
393 self.pipeline.dispose(factory, aux);
394
395 unsafe {
396 factory
397 .device()
398 .destroy_graphics_pipeline(self.graphics_pipeline);
399 factory
400 .device()
401 .destroy_pipeline_layout(self.pipeline_layout);
402 drop(self.set_layouts);
403 }
404 }
405}
406
407fn push_vertex_desc(
408 elements: &[rendy_core::hal::pso::Element<rendy_core::hal::format::Format>],
409 stride: rendy_core::hal::pso::ElemStride,
410 rate: rendy_core::hal::pso::VertexInputRate,
411 vertex_buffers: &mut Vec<rendy_core::hal::pso::VertexBufferDesc>,
412 attributes: &mut Vec<rendy_core::hal::pso::AttributeDesc>,
413) {
414 let index = vertex_buffers.len() as rendy_core::hal::pso::BufferIndex;
415
416 vertex_buffers.push(rendy_core::hal::pso::VertexBufferDesc {
417 binding: index,
418 stride,
419 rate,
420 });
421
422 let mut location = attributes.last().map_or(0, |a| a.location + 1);
423 for &element in elements {
424 attributes.push(rendy_core::hal::pso::AttributeDesc {
425 location,
426 binding: index,
427 element,
428 });
429 location += 1;
430 }
431}