Implement a Render Graph #16
|
@ -81,9 +81,8 @@ struct SlotOwnerPair {
|
|||
slot: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Node {
|
||||
struct Node<'a> {
|
||||
id: u64,
|
||||
desc: RenderGraphPassDesc,
|
||||
desc: &'a RenderGraphPassDesc,
|
||||
slot_inputs: Vec<SlotOwnerPair>,
|
||||
}
|
||||
|
|
|
@ -23,16 +23,13 @@ use wgpu::{util::DeviceExt, RenderPass};
|
|||
use self::execution_path::GraphExecutionPath;
|
||||
|
||||
use super::{
|
||||
compute_pipeline::ComputePipeline,
|
||||
pipeline::Pipeline,
|
||||
render_pipeline::RenderPipeline,
|
||||
renderer::{BasicRenderer, Renderer},
|
||||
renderer::{BasicRenderer, Renderer}, resource::{Pipeline, RenderPipeline},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
//#[derive(Clone)]
|
||||
struct PassEntry {
|
||||
inner: Arc<RefCell<dyn RenderGraphPass>>,
|
||||
desc: RenderGraphPassDesc,
|
||||
desc: Arc<RenderGraphPassDesc>,
|
||||
}
|
||||
|
||||
struct ResourcedSlot {
|
||||
|
@ -115,7 +112,7 @@ impl RenderGraph {
|
|||
}
|
||||
|
||||
pub fn pass(&self, id: u64) -> Option<&RenderGraphPassDesc> {
|
||||
self.passes.get(&id).map(|s| &s.desc)
|
||||
self.passes.get(&id).map(|s| &*s.desc)
|
||||
}
|
||||
|
||||
pub fn add_pass<P: RenderGraphPass>(&mut self, pass: P) {
|
||||
|
@ -150,7 +147,7 @@ impl RenderGraph {
|
|||
desc.id,
|
||||
PassEntry {
|
||||
inner: Arc::new(RefCell::new(pass)),
|
||||
desc,
|
||||
desc: Arc::new(desc),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -162,14 +159,10 @@ impl RenderGraph {
|
|||
|
||||
// For all passes, create their pipelines
|
||||
for pass in self.passes.values() {
|
||||
if let Some(pipei) = &pass.desc.pipeline_info {
|
||||
if let Some(pipei) = &pass.desc.pipeline_desc {
|
||||
let pipeline = match pass.desc.pass_type {
|
||||
RenderPassType::Render => {
|
||||
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: Some(pass.desc.name.as_str()),
|
||||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&pipei.source)),
|
||||
});
|
||||
Pipeline::Render(RenderPipeline::new(device, &self.surface_config, &shader, vec![], vec![]))
|
||||
Pipeline::Render(RenderPipeline::create(device, pipei))
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
|
@ -274,7 +267,7 @@ impl RenderGraph {
|
|||
h.insert(0u64);
|
||||
h
|
||||
};
|
||||
let descs = self.passes.values().map(|p| &p.desc).collect();
|
||||
let descs = self.passes.values().map(|p| &*p.desc).collect();
|
||||
self.exec_path = Some(GraphExecutionPath::new(builtin, descs));
|
||||
}
|
||||
|
||||
|
@ -295,21 +288,25 @@ impl RenderGraph {
|
|||
);
|
||||
window_tv_slot.value = SlotValue::TextureView(view);
|
||||
|
||||
let mut encoders = vec![];
|
||||
while let Some(pass_id) = path.queue.pop_front() {
|
||||
let pass = self.passes.get(&pass_id).unwrap().clone();
|
||||
let label = format!("{} Encoder", pass.desc.name);
|
||||
let pass = self.passes.get(&pass_id).unwrap();
|
||||
let pass_inn = pass.inner.clone();
|
||||
let pass_desc = pass.desc.clone();
|
||||
let label = format!("{} Encoder", pass_desc.name);
|
||||
|
||||
let encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||
label: Some(&label),
|
||||
});
|
||||
let mut context = RenderGraphContext::new(encoder, queue);
|
||||
|
||||
let mut inner = pass.inner.borrow_mut();
|
||||
inner.execute(self, &pass.desc, &mut context);
|
||||
let mut inner = pass_inn.borrow_mut();
|
||||
inner.execute(self, &*pass_desc, &mut context);
|
||||
|
||||
queue.submit(std::iter::once(context.encoder.finish()));
|
||||
encoders.push(context.encoder.finish());
|
||||
}
|
||||
|
||||
queue.submit(encoders.into_iter());
|
||||
output.present();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
use std::collections::HashMap;
|
||||
use std::{collections::HashMap, num::NonZeroU32, rc::Rc};
|
||||
|
||||
use lyra_ecs::World;
|
||||
|
||||
use super::{BufferDescriptor, BufferInitDescriptor, RenderGraph, RenderGraphContext, SamplerDescriptor, TextureDescriptor, TextureViewDescriptor};
|
||||
use crate::render::resource::RenderPipelineDescriptor;
|
||||
|
||||
use super::{
|
||||
BufferDescriptor, BufferInitDescriptor, RenderGraph, RenderGraphContext, SamplerDescriptor,
|
||||
TextureDescriptor, TextureViewDescriptor,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||
pub enum RenderPassType {
|
||||
Compute,
|
||||
#[default]
|
||||
Render
|
||||
Render,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -75,39 +80,83 @@ pub struct RenderPassSlot {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RenderGraphPipelineInfo {
|
||||
pub label: String,
|
||||
pub struct PipelineShaderDesc {
|
||||
pub label: Option<String>,
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
impl RenderGraphPipelineInfo {
|
||||
pub fn new(label: &str, source: &str) -> Self {
|
||||
Self {
|
||||
label: label.to_string(),
|
||||
source: source.to_string(),
|
||||
}
|
||||
}
|
||||
pub entry_point: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RenderGraphPipelineInfo {
|
||||
/// Debug label of the pipeline. This will show up in graphics debuggers for easy identification.
|
||||
pub label: Option<String>,
|
||||
/// The layout of bind groups for this pipeline.
|
||||
pub bind_group_layouts: Vec<Rc<wgpu::BindGroupLayout>>,
|
||||
/// The descriptor of the vertex shader.
|
||||
pub vertex: PipelineShaderDesc,
|
||||
/// The properties of the pipeline at the primitive assembly and rasterization level.
|
||||
pub primitive: wgpu::PrimitiveState,
|
||||
/// The effect of draw calls on the depth and stencil aspects of the output target, if any.
|
||||
pub depth_stencil: Option<wgpu::DepthStencilState>,
|
||||
/// The multi-sampling properties of the pipeline.
|
||||
pub multisample: wgpu::MultisampleState,
|
||||
/// The compiled fragment stage, its entry point, and the color targets.
|
||||
pub fragment: Option<PipelineShaderDesc>,
|
||||
/// If the pipeline will be used with a multiview render pass, this indicates how many array
|
||||
/// layers the attachments will have.
|
||||
pub multiview: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
impl RenderGraphPipelineInfo {
|
||||
pub fn new(
|
||||
label: &str,
|
||||
bind_group_layouts: Vec<wgpu::BindGroupLayout>,
|
||||
vertex: PipelineShaderDesc,
|
||||
primitive: wgpu::PrimitiveState,
|
||||
depth_stencil: Option<wgpu::DepthStencilState>,
|
||||
multisample: wgpu::MultisampleState,
|
||||
fragment: Option<PipelineShaderDesc>,
|
||||
multiview: Option<NonZeroU32>,
|
||||
) -> Self {
|
||||
Self {
|
||||
label: Some(label.to_string()),
|
||||
bind_group_layouts: bind_group_layouts
|
||||
.into_iter()
|
||||
.map(|bgl| Rc::new(bgl))
|
||||
.collect(),
|
||||
vertex,
|
||||
primitive,
|
||||
depth_stencil,
|
||||
multisample,
|
||||
fragment,
|
||||
multiview,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RenderGraphPassDesc {
|
||||
pub id: u64,
|
||||
pub name: String,
|
||||
pub pass_type: RenderPassType,
|
||||
pub slots: Vec<RenderPassSlot>,
|
||||
slot_names: HashMap<String, u64>,
|
||||
pub pipeline_info: Option<RenderGraphPipelineInfo>,
|
||||
pub pipeline_desc: Option<RenderPipelineDescriptor>,
|
||||
}
|
||||
|
||||
impl RenderGraphPassDesc {
|
||||
pub fn new(id: u64, name: &str, pass_type: RenderPassType, pipeline_info: Option<RenderGraphPipelineInfo>) -> Self {
|
||||
pub fn new(
|
||||
id: u64,
|
||||
name: &str,
|
||||
pass_type: RenderPassType,
|
||||
pipeline_desc: Option<RenderPipelineDescriptor>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name: name.to_string(),
|
||||
pass_type,
|
||||
slots: vec![],
|
||||
slot_names: HashMap::default(),
|
||||
pipeline_info
|
||||
pipeline_desc,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,9 +166,20 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_buffer_slot(&mut self, id: u64, name: &str, attribute: SlotAttribute, desc: Option<SlotDescriptor>) {
|
||||
debug_assert!(matches!(desc, None | Some(SlotDescriptor::Buffer(_)) | Some(SlotDescriptor::BufferInit(_)) ),
|
||||
"slot descriptor does not match the type of slot");
|
||||
pub fn add_buffer_slot(
|
||||
&mut self,
|
||||
id: u64,
|
||||
name: &str,
|
||||
attribute: SlotAttribute,
|
||||
desc: Option<SlotDescriptor>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(
|
||||
desc,
|
||||
None | Some(SlotDescriptor::Buffer(_)) | Some(SlotDescriptor::BufferInit(_))
|
||||
),
|
||||
"slot descriptor does not match the type of slot"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
id,
|
||||
|
@ -132,9 +192,17 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_texture_slot(&mut self, id: u64, name: &str, attribute: SlotAttribute, desc: Option<SlotDescriptor>) {
|
||||
debug_assert!(matches!(desc, None | Some(SlotDescriptor::Texture(_))),
|
||||
"slot descriptor does not match the type of slot");
|
||||
pub fn add_texture_slot(
|
||||
&mut self,
|
||||
id: u64,
|
||||
name: &str,
|
||||
attribute: SlotAttribute,
|
||||
desc: Option<SlotDescriptor>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(desc, None | Some(SlotDescriptor::Texture(_))),
|
||||
"slot descriptor does not match the type of slot"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
id,
|
||||
|
@ -147,9 +215,17 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_texture_view_slot(&mut self, id: u64, name: &str, attribute: SlotAttribute, desc: Option<SlotDescriptor>) {
|
||||
debug_assert!(matches!(desc, None | Some(SlotDescriptor::TextureView(_))),
|
||||
"slot descriptor does not match the type of slot");
|
||||
pub fn add_texture_view_slot(
|
||||
&mut self,
|
||||
id: u64,
|
||||
name: &str,
|
||||
attribute: SlotAttribute,
|
||||
desc: Option<SlotDescriptor>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(desc, None | Some(SlotDescriptor::TextureView(_))),
|
||||
"slot descriptor does not match the type of slot"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
id,
|
||||
|
@ -162,9 +238,17 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_sampler_slot(&mut self, id: u64, name: &str, attribute: SlotAttribute, desc: Option<SlotDescriptor>) {
|
||||
debug_assert!(matches!(desc, None | Some(SlotDescriptor::Sampler(_))),
|
||||
"slot descriptor does not match the type of slot");
|
||||
pub fn add_sampler_slot(
|
||||
&mut self,
|
||||
id: u64,
|
||||
name: &str,
|
||||
attribute: SlotAttribute,
|
||||
desc: Option<SlotDescriptor>,
|
||||
) {
|
||||
debug_assert!(
|
||||
matches!(desc, None | Some(SlotDescriptor::Sampler(_))),
|
||||
"slot descriptor does not match the type of slot"
|
||||
);
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
id,
|
||||
|
@ -198,5 +282,10 @@ pub trait RenderGraphPass: 'static {
|
|||
fn desc<'a, 'b>(&'a self, graph: &'b mut RenderGraph) -> RenderGraphPassDesc;
|
||||
|
||||
fn prepare(&mut self, world: &mut World, context: &mut RenderGraphContext);
|
||||
fn execute(&mut self, graph: &mut RenderGraph, desc: &RenderGraphPassDesc, context: &mut RenderGraphContext);
|
||||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut RenderGraph,
|
||||
desc: &RenderGraphPassDesc,
|
||||
context: &mut RenderGraphContext,
|
||||
);
|
||||
}
|
|
@ -5,9 +5,9 @@ mod base;
|
|||
pub use base::*;
|
||||
|
||||
mod depth_prepass;
|
||||
pub use depth_prepass::*;
|
||||
pub use depth_prepass::*; */
|
||||
|
||||
mod simple_phong;
|
||||
/* mod simple_phong;
|
||||
pub use simple_phong::*; */
|
||||
|
||||
mod triangle;
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use glam::UVec2;
|
||||
use tracing::warn;
|
||||
use wgpu::include_wgsl;
|
||||
|
||||
use crate::{
|
||||
render::{
|
||||
camera::{CameraUniform, RenderCamera},
|
||||
graph::{
|
||||
BufferInitDescriptor, RenderGraphContext, RenderGraphPass, RenderGraphPassDesc,
|
||||
RenderGraphPipelineInfo, RenderPassType, SlotAttribute, SlotDescriptor,
|
||||
BufferInitDescriptor, PipelineShaderDesc, RenderGraphContext, RenderGraphPass,
|
||||
RenderGraphPassDesc, RenderGraphPipelineInfo, RenderPassType, SlotAttribute,
|
||||
SlotDescriptor,
|
||||
},
|
||||
renderer::ScreenSize,
|
||||
resource::{FragmentState, RenderPipelineDescriptor, Shader, VertexState},
|
||||
},
|
||||
scene::CameraComponent,
|
||||
};
|
||||
|
@ -30,17 +35,46 @@ impl RenderGraphPass for TrianglePass {
|
|||
&self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::RenderGraphPassDesc {
|
||||
let shader = Rc::new(Shader {
|
||||
label: Some("triangle_shader".into()),
|
||||
source: include_str!("../../shaders/triangle.wgsl").to_string(),
|
||||
});
|
||||
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
graph.next_id(),
|
||||
"TrianglePass",
|
||||
RenderPassType::Render,
|
||||
Some(RenderGraphPipelineInfo::new(
|
||||
"TriangleShader",
|
||||
include_str!("../../shaders/triangle.wgsl"),
|
||||
)),
|
||||
Some(RenderPipelineDescriptor {
|
||||
label: Some("triangle_pipeline".into()),
|
||||
layouts: vec![],
|
||||
push_constant_ranges: vec![],
|
||||
vertex: VertexState {
|
||||
module: shader.clone(),
|
||||
entry_point: "vs_main".into(),
|
||||
buffers: vec![],
|
||||
},
|
||||
fragment: Some(FragmentState {
|
||||
module: shader,
|
||||
entry_point: "fs_main".into(),
|
||||
targets: vec![Some(wgpu::ColorTargetState {
|
||||
format: graph.surface_config.format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
depth_stencil: None,
|
||||
primitive: wgpu::PrimitiveState::default(),
|
||||
multisample: wgpu::MultisampleState::default(),
|
||||
multiview: None,
|
||||
}),
|
||||
);
|
||||
|
||||
desc.add_texture_view_slot(graph.next_id(), "window_texture_view", SlotAttribute::Input, None);
|
||||
desc.add_texture_view_slot(
|
||||
graph.next_id(),
|
||||
"window_texture_view",
|
||||
SlotAttribute::Input,
|
||||
None,
|
||||
);
|
||||
|
||||
/* desc.add_buffer_slot(graph.next_id(), "screen_size_buffer", SlotAttribute::Output, Some(SlotDescriptor::BufferInit(BufferInitDescriptor {
|
||||
label: Some("B_ScreenSize".to_string()),
|
||||
|
@ -64,7 +98,10 @@ impl RenderGraphPass for TrianglePass {
|
|||
desc: &crate::render::graph::RenderGraphPassDesc,
|
||||
context: &mut crate::render::graph::RenderGraphContext,
|
||||
) {
|
||||
let view = graph.slot_value(graph.slot_id("window_texture_view").unwrap()).unwrap().as_texture_view();
|
||||
let view = graph
|
||||
.slot_value(graph.slot_id("window_texture_view").unwrap())
|
||||
.unwrap()
|
||||
.as_texture_view();
|
||||
let encoder = &mut context.encoder;
|
||||
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
pub mod renderer;
|
||||
pub mod render_pipeline;
|
||||
pub mod compute_pipeline;
|
||||
pub mod pipeline;
|
||||
pub mod resource;
|
||||
pub mod vertex;
|
||||
pub mod desc_buf_lay;
|
||||
pub mod render_buffer;
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
use std::{collections::HashMap, ops::Deref};
|
||||
|
||||
use wgpu::{PipelineLayout, VertexBufferLayout, BindGroupLayout};
|
||||
|
||||
use super::texture::RenderTexture;
|
||||
|
||||
pub struct RenderPipeline {
|
||||
layout: PipelineLayout,
|
||||
wgpu_pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl Deref for RenderPipeline {
|
||||
type Target = wgpu::RenderPipeline;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.wgpu_pipeline
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderPipeline {
|
||||
/// Creates the default render pipeline
|
||||
pub fn new(device: &wgpu::Device, config: &wgpu::SurfaceConfiguration, shader: &wgpu::ShaderModule, buffer_layouts: Vec<VertexBufferLayout>, bind_group_layouts: Vec<&BindGroupLayout>) -> RenderPipeline {
|
||||
let render_pipeline_layout =
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: Some("Render Pipeline Layout"),
|
||||
bind_group_layouts: &bind_group_layouts,
|
||||
push_constant_ranges: &[],
|
||||
});
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||
label: Some("Render Pipeline"),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: shader,
|
||||
entry_point: "vs_main",
|
||||
buffers: &buffer_layouts,
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: shader,
|
||||
entry_point: "fs_main",
|
||||
targets: &[Some(wgpu::ColorTargetState {
|
||||
format: config.format,
|
||||
blend: Some(wgpu::BlendState::REPLACE),
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||
strip_index_format: None,
|
||||
front_face: wgpu::FrontFace::Ccw,
|
||||
cull_mode: Some(wgpu::Face::Back),
|
||||
// Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE
|
||||
polygon_mode: wgpu::PolygonMode::Fill,
|
||||
// Requires Features::DEPTH_CLIP_CONTROL
|
||||
unclipped_depth: false,
|
||||
// Requires Features::CONSERVATIVE_RASTERIZATION
|
||||
conservative: false,
|
||||
},
|
||||
/*depth_stencil: Some(wgpu::DepthStencilState {
|
||||
format: RenderTexture::DEPTH_FORMAT,
|
||||
depth_write_enabled: true,
|
||||
depth_compare: wgpu::CompareFunction::Less,
|
||||
stencil: wgpu::StencilState::default(), // TODO: stencil buffer
|
||||
bias: wgpu::DepthBiasState::default(),
|
||||
}),*/
|
||||
depth_stencil: None,
|
||||
multisample: wgpu::MultisampleState {
|
||||
count: 1,
|
||||
mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
},
|
||||
multiview: None,
|
||||
});
|
||||
|
||||
Self {
|
||||
layout: render_pipeline_layout,
|
||||
wgpu_pipeline: render_pipeline,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn layout(&self) -> &PipelineLayout {
|
||||
&self.layout
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn wgpu_pipeline(&self) -> &wgpu::RenderPipeline {
|
||||
&self.wgpu_pipeline
|
||||
}
|
||||
}
|
|
@ -1,41 +1,29 @@
|
|||
use std::collections::{VecDeque, HashSet};
|
||||
use std::collections::VecDeque;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::borrow::Cow;
|
||||
|
||||
use glam::Vec3;
|
||||
use itertools::izip;
|
||||
use lyra_ecs::query::filter::{Has, Not, Or};
|
||||
use lyra_ecs::relation::{ChildOf, RelationOriginComponent};
|
||||
use lyra_ecs::{Component, Entity};
|
||||
use lyra_ecs::query::{Entities, Res, TickOf};
|
||||
use lyra_ecs::Component;
|
||||
use lyra_ecs::World;
|
||||
use lyra_scene::{SceneGraph, WorldTransform};
|
||||
use lyra_scene::SceneGraph;
|
||||
use tracing::{debug, instrument, warn};
|
||||
use uuid::Uuid;
|
||||
use wgpu::{BindGroupLayout, Limits};
|
||||
use wgpu::util::DeviceExt;
|
||||
use wgpu::Limits;
|
||||
use winit::window::Window;
|
||||
|
||||
use crate::math::Transform;
|
||||
use crate::render::graph::TrianglePass;
|
||||
use crate::render::material::MaterialUniform;
|
||||
use crate::render::render_buffer::BufferWrapperBuilder;
|
||||
use crate::scene::CameraComponent;
|
||||
use crate::DeltaTime;
|
||||
|
||||
use super::camera::{RenderCamera, CameraUniform};
|
||||
use super::desc_buf_lay::DescVertexBufferLayout;
|
||||
use super::camera::CameraUniform;
|
||||
use super::graph::RenderGraph;
|
||||
use super::light::LightUniformBuffers;
|
||||
use super::light_cull_compute::LightCullCompute;
|
||||
use super::material::Material;
|
||||
use super::render_buffer::BufferWrapper;
|
||||
use super::texture::RenderTexture;
|
||||
use super::transform_buffer_storage::{TransformBuffers, TransformGroup};
|
||||
use super::vertex::Vertex;
|
||||
use super::{render_pipeline::RenderPipeline, render_buffer::BufferStorage, render_job::RenderJob};
|
||||
use super::transform_buffer_storage::TransformBuffers;
|
||||
use super::{resource::RenderPipeline, render_buffer::BufferStorage, render_job::RenderJob};
|
||||
|
||||
use lyra_resource::{gltf::Mesh, ResHandle};
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
mod pipeline;
|
||||
pub use pipeline::*;
|
||||
|
||||
mod compute_pipeline;
|
||||
pub use compute_pipeline::*;
|
||||
|
||||
mod render_pipeline;
|
||||
pub use render_pipeline::*;
|
|
@ -0,0 +1,228 @@
|
|||
use std::{num::NonZeroU32, ops::Deref, rc::Rc};
|
||||
|
||||
use wgpu::{BindGroupLayout, PipelineLayout};
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct VertexBufferLayout {
|
||||
pub array_stride: wgpu::BufferAddress,
|
||||
pub step_mode: wgpu::VertexStepMode,
|
||||
pub attributes: Vec<wgpu::VertexAttribute>,
|
||||
}
|
||||
|
||||
/// Describes the vertex stage in a render pipeline.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VertexState {
|
||||
// TODO: make this a ResHandle<Shader>
|
||||
/// The compiled shader module for the stage.
|
||||
pub module: Rc<Shader>,
|
||||
/// The entry point in the compiled shader.
|
||||
/// There must be a function in the shader with the same name.
|
||||
pub entry_point: String,
|
||||
/// The format of the vertex buffers used with this pipeline.
|
||||
pub buffers: Vec<VertexBufferLayout>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Shader {
|
||||
pub label: Option<String>,
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
/// Describes the fragment stage in the render pipeline.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FragmentState {
|
||||
// TODO: make this a ResHandle<Shader>
|
||||
/// The compiled shader module for the stage.
|
||||
pub module: Rc<Shader>,
|
||||
/// The entry point in the compiled shader.
|
||||
/// There must be a function in the shader with the same name.
|
||||
pub entry_point: String,
|
||||
/// The color state of the render targets.
|
||||
pub targets: Vec<Option<wgpu::ColorTargetState>>,
|
||||
}
|
||||
|
||||
//#[derive(Debug, Clone)]
|
||||
pub struct RenderPipelineDescriptor {
|
||||
pub label: Option<String>,
|
||||
pub layouts: Vec<wgpu::BindGroupLayout>,
|
||||
pub push_constant_ranges: Vec<wgpu::PushConstantRange>,
|
||||
pub vertex: VertexState,
|
||||
pub fragment: Option<FragmentState>,
|
||||
pub primitive: wgpu::PrimitiveState,
|
||||
pub depth_stencil: Option<wgpu::DepthStencilState>,
|
||||
pub multisample: wgpu::MultisampleState,
|
||||
pub multiview: Option<NonZeroU32>,
|
||||
}
|
||||
|
||||
impl RenderPipelineDescriptor {
|
||||
/// Create the [`wgpu::PipelineLayout`] for this pipeline
|
||||
pub(crate) fn create_layout(&self, device: &wgpu::Device) -> wgpu::PipelineLayout {
|
||||
let bgs = self.layouts.iter().collect::<Vec<_>>();
|
||||
|
||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
label: None, //self.label.as_ref().map(|s| format!("{}Layout", s)),
|
||||
bind_group_layouts: &bgs,
|
||||
push_constant_ranges: &self.push_constant_ranges,
|
||||
});
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
/* fn as_wgpu<'a>(&'a self, device: &wgpu::Device, layout: Option<&'a wgpu::PipelineLayout>) -> wgpu::RenderPipelineDescriptor<'a> {
|
||||
let vbuffers = self.vertex.buffers.iter().map(|vbl| {
|
||||
wgpu::VertexBufferLayout {
|
||||
array_stride: vbl.array_stride,
|
||||
step_mode: vbl.step_mode,
|
||||
attributes: &vbl.attributes
|
||||
}
|
||||
}).collect::<Vec<_>>();
|
||||
let vmodule = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: self.vertex.module.label.as_ref().map(|s| s.as_str()),
|
||||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&self.vertex.module.source)),
|
||||
});
|
||||
let vstate = wgpu::VertexState {
|
||||
module: &vmodule,
|
||||
entry_point: &self.vertex.entry_point,
|
||||
buffers: &vbuffers,
|
||||
};
|
||||
|
||||
let fmodule = self.fragment.as_ref().map(|f| {
|
||||
device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: f.module.label.as_ref().map(|s| s.as_str()),
|
||||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&f.module.source)),
|
||||
})
|
||||
});
|
||||
|
||||
let fstate = self.fragment.as_ref().map(move |f| {
|
||||
wgpu::FragmentState {
|
||||
module: fmodule.as_ref().unwrap(),
|
||||
entry_point: &f.entry_point,
|
||||
targets: &f.targets,
|
||||
}
|
||||
});
|
||||
|
||||
wgpu::RenderPipelineDescriptor {
|
||||
label: self.label.as_deref(),
|
||||
layout,
|
||||
vertex: vstate,
|
||||
primitive: self.primitive,
|
||||
depth_stencil: self.depth_stencil,
|
||||
multisample: self.multisample,
|
||||
fragment: fstate,
|
||||
multiview: self.multiview,
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
pub struct RenderPipeline {
|
||||
layout: Option<PipelineLayout>,
|
||||
wgpu_pipeline: wgpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl Deref for RenderPipeline {
|
||||
type Target = wgpu::RenderPipeline;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.wgpu_pipeline
|
||||
}
|
||||
}
|
||||
|
||||
impl From<wgpu::RenderPipeline> for RenderPipeline {
|
||||
fn from(value: wgpu::RenderPipeline) -> Self {
|
||||
Self {
|
||||
layout: None,
|
||||
wgpu_pipeline: value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderPipeline {
|
||||
/// Creates the default render pipeline
|
||||
///
|
||||
/// Parameters:
|
||||
/// * `device` - The device to create the pipeline on.
|
||||
/// * `config` - The surface config to use to create the pipeline.
|
||||
/// * `label` - The label of the pipeline.
|
||||
/// * `shader` - The compiled shader of the pipeline.
|
||||
/// * `vertex_entry_point` - The entry point name of the vertex shader
|
||||
pub fn create(device: &wgpu::Device, desc: &RenderPipelineDescriptor) -> RenderPipeline {
|
||||
// create the layout only if bind groups layouts were specified
|
||||
let layout = if !desc.layouts.is_empty() {
|
||||
Some(desc.create_layout(device))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let vrtx_buffs = desc
|
||||
.vertex
|
||||
.buffers
|
||||
.iter()
|
||||
.map(|vbl| wgpu::VertexBufferLayout {
|
||||
array_stride: vbl.array_stride,
|
||||
step_mode: vbl.step_mode,
|
||||
attributes: &vbl.attributes,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// an Rc was used here so that this shader could be reused by the fragment stage if
|
||||
// they share the same shader. I tried to do it without an Rc but couldn't get past
|
||||
// the borrow checker
|
||||
let vrtx_shad = Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: desc.vertex.module.label.as_ref().map(|s| s.as_str()),
|
||||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(
|
||||
&desc.vertex.module.source,
|
||||
)),
|
||||
}));
|
||||
let vrtx_state = wgpu::VertexState {
|
||||
module: &*vrtx_shad,
|
||||
entry_point: &desc.vertex.entry_point,
|
||||
buffers: &vrtx_buffs,
|
||||
};
|
||||
|
||||
let frag_module = desc.fragment.as_ref().map(|f| {
|
||||
if f.module == desc.vertex.module {
|
||||
vrtx_shad.clone()
|
||||
} else {
|
||||
Rc::new(device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||
label: f.module.label.as_ref().map(|s| s.as_str()),
|
||||
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(&f.module.source)),
|
||||
}))
|
||||
}
|
||||
});
|
||||
|
||||
let fm = frag_module.as_ref();
|
||||
let fstate = desc.fragment.as_ref().map(move |f| wgpu::FragmentState {
|
||||
module: fm.unwrap(),
|
||||
entry_point: &f.entry_point,
|
||||
targets: &f.targets,
|
||||
});
|
||||
|
||||
let render_desc = wgpu::RenderPipelineDescriptor {
|
||||
label: desc.label.as_deref(),
|
||||
layout: layout.as_ref(),
|
||||
vertex: vrtx_state,
|
||||
primitive: desc.primitive,
|
||||
depth_stencil: desc.depth_stencil.clone(),
|
||||
multisample: desc.multisample,
|
||||
fragment: fstate,
|
||||
multiview: desc.multiview,
|
||||
};
|
||||
|
||||
let render_pipeline = device.create_render_pipeline(&render_desc);
|
||||
|
||||
Self {
|
||||
layout,
|
||||
wgpu_pipeline: render_pipeline,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn layout(&self) -> Option<&PipelineLayout> {
|
||||
self.layout.as_ref()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn wgpu_pipeline(&self) -> &wgpu::RenderPipeline {
|
||||
&self.wgpu_pipeline
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue