Implement a Render Graph #16
|
@ -0,0 +1,29 @@
|
|||
# The run config is used for both run mode and debug mode
|
||||
|
||||
[[configs]]
|
||||
# the name of this task
|
||||
name = "Example 'simple_scene'"
|
||||
|
||||
# the type of the debugger. If not set, it can't be debugged but can still be run
|
||||
type = "lldb"
|
||||
|
||||
# the program to run
|
||||
program = "../../target/debug/simple_scene"
|
||||
|
||||
# the program arguments, e.g. args = ["arg1", "arg2"], optional
|
||||
# args = []
|
||||
|
||||
# current working directory, optional
|
||||
cwd = "${workspace}/examples/simple_scene"
|
||||
|
||||
# environment variables, optional
|
||||
# [configs.env]
|
||||
# VAR1 = "VAL1"
|
||||
# VAR2 = "VAL2"
|
||||
|
||||
# task to run before the run/debug session is started, optional
|
||||
[configs.prelaunch]
|
||||
program = "cargo"
|
||||
args = [
|
||||
"build",
|
||||
]
|
|
@ -3065,6 +3065,16 @@ version = "0.3.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
|
||||
|
||||
[[package]]
|
||||
name = "simple_scene"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-std",
|
||||
"lyra-engine",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.9"
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
[package]
|
||||
name = "simple_scene"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
lyra-engine = { path = "../../", features = ["tracy"] }
|
||||
anyhow = "1.0.75"
|
||||
async-std = "1.12.0"
|
||||
tracing = "0.1.37"
|
|
@ -0,0 +1,59 @@
|
|||
---Return the userdata's name from its metatable
|
||||
---@param val userdata
|
||||
---@return string
|
||||
function udname(val)
|
||||
return getmetatable(val).__name
|
||||
end
|
||||
|
||||
function on_init()
|
||||
local cube = world:request_res("../assets/cube-texture-embedded.gltf")
|
||||
print("Loaded textured cube (" .. udname(cube) .. ")")
|
||||
|
||||
cube:wait_until_loaded()
|
||||
local scenes = cube:scenes()
|
||||
local cube_scene = scenes[1]
|
||||
|
||||
local pos = Transform.from_translation(Vec3.new(0, 0, -8.0))
|
||||
|
||||
local e = world:spawn(pos, cube_scene)
|
||||
print("spawned entity " .. tostring(e))
|
||||
end
|
||||
|
||||
--[[ function on_first()
|
||||
print("Lua's first function was called")
|
||||
end
|
||||
|
||||
function on_pre_update()
|
||||
print("Lua's pre-update function was called")
|
||||
end ]]
|
||||
|
||||
function on_update()
|
||||
--[[ ---@type number
|
||||
local dt = world:resource(DeltaTime)
|
||||
local act = world:resource(ActionHandler)
|
||||
---@type number
|
||||
local move_objs = act:get_axis("ObjectsMoveUpDown")
|
||||
|
||||
world:view(function (t)
|
||||
if move_objs ~= nil then
|
||||
t:translate(0, move_objs * 0.35 * dt, 0)
|
||||
return t
|
||||
end
|
||||
end, Transform) ]]
|
||||
|
||||
---@type number
|
||||
local dt = world:resource(DeltaTime)
|
||||
|
||||
world:view(function (t)
|
||||
t:translate(0, 0.15 * dt, 0)
|
||||
return t
|
||||
end, Transform)
|
||||
end
|
||||
|
||||
--[[ function on_post_update()
|
||||
print("Lua's post-update function was called")
|
||||
end
|
||||
|
||||
function on_last()
|
||||
print("Lua's last function was called")
|
||||
end ]]
|
|
@ -0,0 +1,149 @@
|
|||
use lyra_engine::{
|
||||
assets::{gltf::Gltf, ResourceManager},
|
||||
game::Game,
|
||||
input::{
|
||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
||||
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
|
||||
},
|
||||
math::{self, Transform, Vec3},
|
||||
render::light::directional::DirectionalLight,
|
||||
scene::{
|
||||
CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, WorldTransform,
|
||||
ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN,
|
||||
ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
|
||||
},
|
||||
};
|
||||
|
||||
#[async_std::main]
|
||||
async fn main() {
|
||||
let action_handler_plugin = |game: &mut Game| {
|
||||
let action_handler = ActionHandler::builder()
|
||||
.add_layout(LayoutId::from(0))
|
||||
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
||||
.add_action(ACTLBL_MOVE_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
||||
.add_action(ACTLBL_MOVE_UP_DOWN, Action::new(ActionKind::Axis))
|
||||
.add_action(ACTLBL_LOOK_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
||||
.add_action(ACTLBL_LOOK_UP_DOWN, Action::new(ActionKind::Axis))
|
||||
.add_action(ACTLBL_LOOK_ROLL, Action::new(ActionKind::Axis))
|
||||
.add_action("Debug", Action::new(ActionKind::Button))
|
||||
.add_mapping(
|
||||
ActionMapping::builder(LayoutId::from(0), ActionMappingId::from(0))
|
||||
.bind(
|
||||
ACTLBL_MOVE_FORWARD_BACKWARD,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_MOVE_LEFT_RIGHT,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_MOVE_UP_DOWN,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_LOOK_LEFT_RIGHT,
|
||||
&[
|
||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(),
|
||||
ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_LOOK_UP_DOWN,
|
||||
&[
|
||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(),
|
||||
ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
ACTLBL_LOOK_ROLL,
|
||||
&[
|
||||
ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0),
|
||||
],
|
||||
)
|
||||
.bind(
|
||||
"Debug",
|
||||
&[ActionSource::Keyboard(KeyCode::B).into_binding()],
|
||||
)
|
||||
.finish(),
|
||||
)
|
||||
.finish();
|
||||
|
||||
let world = game.world_mut();
|
||||
world.add_resource(action_handler);
|
||||
game.with_plugin(InputActionPlugin);
|
||||
};
|
||||
|
||||
Game::initialize()
|
||||
.await
|
||||
.with_plugin(lyra_engine::DefaultPlugins)
|
||||
.with_plugin(setup_scene_plugin)
|
||||
.with_plugin(action_handler_plugin)
|
||||
//.with_plugin(camera_debug_plugin)
|
||||
.with_plugin(FreeFlyCameraPlugin)
|
||||
.run()
|
||||
.await;
|
||||
}
|
||||
|
||||
fn setup_scene_plugin(game: &mut Game) {
|
||||
let world = game.world_mut();
|
||||
let resman = world.get_resource_mut::<ResourceManager>();
|
||||
|
||||
/* let camera_gltf = resman
|
||||
.request::<Gltf>("../assets/AntiqueCamera.glb")
|
||||
.unwrap();
|
||||
|
||||
camera_gltf.wait_recurse_dependencies_load();
|
||||
let camera_mesh = &camera_gltf.data_ref().unwrap().scenes[0];
|
||||
drop(resman);
|
||||
|
||||
world.spawn((
|
||||
camera_mesh.clone(),
|
||||
WorldTransform::default(),
|
||||
Transform::from_xyz(0.0, -5.0, -2.0),
|
||||
)); */
|
||||
|
||||
let cube_gltf = resman
|
||||
.request::<Gltf>("../assets/cube-texture-embedded.gltf")
|
||||
.unwrap();
|
||||
|
||||
cube_gltf.wait_recurse_dependencies_load();
|
||||
let cube_mesh = &cube_gltf.data_ref().unwrap().scenes[0];
|
||||
drop(resman);
|
||||
|
||||
world.spawn((
|
||||
cube_mesh.clone(),
|
||||
WorldTransform::default(),
|
||||
Transform::from_xyz(0.0, -5.0, -2.0),
|
||||
));
|
||||
|
||||
{
|
||||
let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0);
|
||||
light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
|
||||
light_tran.rotate_x(math::Angle::Degrees(-45.0));
|
||||
light_tran.rotate_y(math::Angle::Degrees(25.0));
|
||||
world.spawn((
|
||||
DirectionalLight {
|
||||
enabled: true,
|
||||
color: Vec3::ONE,
|
||||
intensity: 0.15, //..Default::default()
|
||||
},
|
||||
light_tran,
|
||||
));
|
||||
}
|
||||
|
||||
let mut camera = CameraComponent::new_3d();
|
||||
camera.transform.translation += math::Vec3::new(0.0, 0.0, 5.5);
|
||||
world.spawn((camera, FreeFlyCamera::default()));
|
||||
}
|
|
@ -57,10 +57,12 @@ struct GameLoop {
|
|||
}
|
||||
|
||||
impl GameLoop {
|
||||
pub async fn new(window: Arc<Window>, world: World, staged_exec: StagedExecutor) -> GameLoop {
|
||||
pub async fn new(window: Arc<Window>, mut world: World, staged_exec: StagedExecutor) -> Self {
|
||||
let renderer = BasicRenderer::create_with_window(&mut world, window.clone()).await;
|
||||
|
||||
Self {
|
||||
window: Arc::clone(&window),
|
||||
renderer: Box::new(BasicRenderer::create_with_window(window).await),
|
||||
renderer: Box::new(renderer),
|
||||
|
||||
world,
|
||||
staged_exec,
|
||||
|
@ -68,7 +70,7 @@ impl GameLoop {
|
|||
}
|
||||
|
||||
pub async fn on_resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
|
||||
self.renderer.on_resize(new_size);
|
||||
self.renderer.on_resize(&mut self.world, new_size);
|
||||
}
|
||||
|
||||
pub async fn on_init(&mut self) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#![feature(hash_extract_if)]
|
||||
#![feature(lint_reasons)]
|
||||
#![feature(trait_alias)]
|
||||
#![feature(map_many_mut)]
|
||||
|
||||
extern crate self as lyra_engine;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct GraphExecutionPath {
|
|||
}
|
||||
|
||||
impl GraphExecutionPath {
|
||||
pub fn new(pass_descriptions: Vec<&RenderGraphPassDesc>) -> Self {
|
||||
pub fn new(built_in_slots: FxHashSet<u64>, pass_descriptions: Vec<&RenderGraphPassDesc>) -> Self {
|
||||
// collect all the output slots
|
||||
let mut total_outputs = HashMap::new();
|
||||
for desc in pass_descriptions.iter() {
|
||||
|
@ -28,6 +28,9 @@ impl GraphExecutionPath {
|
|||
// find the node inputs
|
||||
let mut inputs = vec![];
|
||||
for slot in desc.input_slots() {
|
||||
// If the slot is built in to the graph, no need to care about the sorting.
|
||||
if built_in_slots.contains(&slot.id) { continue; }
|
||||
|
||||
let inp = total_outputs.get(&slot.name)
|
||||
.expect(&format!("failed to find slot: '{}', ensure that there is a pass outputting it", slot.name));
|
||||
inputs.push(*inp);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
mod pass;
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{HashMap, VecDeque},
|
||||
ptr::NonNull,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub use pass::*;
|
||||
|
||||
|
@ -11,14 +16,22 @@ pub use slot_desc::*;
|
|||
|
||||
mod execution_path;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
use tracing::debug;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use tracing::{debug, debug_span, instrument};
|
||||
use wgpu::{util::DeviceExt, RenderPass};
|
||||
|
||||
use super::{compute_pipeline::ComputePipeline, pipeline::Pipeline, render_pipeline::RenderPipeline, renderer::{BasicRenderer, Renderer}};
|
||||
use self::execution_path::GraphExecutionPath;
|
||||
|
||||
use super::{
|
||||
compute_pipeline::ComputePipeline,
|
||||
pipeline::Pipeline,
|
||||
render_pipeline::RenderPipeline,
|
||||
renderer::{BasicRenderer, Renderer},
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
struct PassEntry {
|
||||
inner: Box<dyn RenderGraphPass>,
|
||||
inner: Arc<RefCell<dyn RenderGraphPass>>,
|
||||
desc: RenderGraphPassDesc,
|
||||
}
|
||||
|
||||
|
@ -35,7 +48,7 @@ struct ResourcedSlot {
|
|||
}
|
||||
|
||||
/// Stores the pipeline and other resources it uses.
|
||||
///
|
||||
///
|
||||
/// This stores the bind groups that have been created for it
|
||||
pub struct PipelineResource {
|
||||
pub pipeline: Pipeline,
|
||||
|
@ -46,80 +59,137 @@ pub struct PipelineResource {
|
|||
pub struct RenderGraph {
|
||||
slots: FxHashMap<u64, ResourcedSlot>,
|
||||
slot_names: HashMap<String, u64>,
|
||||
// slots with same name
|
||||
slot_mutlikey: FxHashMap<u64, u64>,
|
||||
passes: FxHashMap<u64, PassEntry>,
|
||||
// TODO: Use a SlotMap
|
||||
bind_groups: FxHashMap<u64, wgpu::BindGroup>,
|
||||
// TODO: make pipelines a `type` parameter in RenderPasses,
|
||||
// then the pipelines can be retrieved via TypeId to the pass.
|
||||
pipelines: HashMap<String, PipelineResource>,
|
||||
///
|
||||
pipelines: FxHashMap<u64, PipelineResource>,
|
||||
current_id: u64,
|
||||
exec_path: Option<GraphExecutionPath>,
|
||||
|
||||
pub(crate) surface_config: wgpu::SurfaceConfiguration,
|
||||
}
|
||||
|
||||
impl RenderGraph {
|
||||
pub fn new(surface_config: wgpu::SurfaceConfiguration) -> Self {
|
||||
let mut slots = FxHashMap::default();
|
||||
let mut slot_names = HashMap::default();
|
||||
|
||||
slots.insert(
|
||||
0,
|
||||
ResourcedSlot {
|
||||
name: "window_texture_view".to_string(),
|
||||
ty: SlotType::TextureView,
|
||||
value: SlotValue::None,
|
||||
bind_group_id: None,
|
||||
create_desc: None,
|
||||
},
|
||||
);
|
||||
slot_names.insert("window_texture_view".to_string(), 0u64);
|
||||
|
||||
Self {
|
||||
slots: Default::default(),
|
||||
slot_names: Default::default(),
|
||||
slot_mutlikey: Default::default(),
|
||||
slots,
|
||||
slot_names,
|
||||
passes: Default::default(),
|
||||
bind_groups: Default::default(),
|
||||
pipelines: Default::default(),
|
||||
current_id: 0,
|
||||
current_id: 1,
|
||||
exec_path: None,
|
||||
surface_config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn next_id(&mut self) -> u64 {
|
||||
self.current_id += 1;
|
||||
self.current_id
|
||||
}
|
||||
|
||||
pub fn slot_id(&self, name: &str) -> Option<u64> {
|
||||
self.slot_names.get(name).cloned()
|
||||
}
|
||||
|
||||
pub fn slot_value(&self, id: u64) -> Option<&SlotValue> {
|
||||
self.slots.get(&id).map(|s| &s.value)
|
||||
}
|
||||
|
||||
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) {
|
||||
let mut desc = pass.desc(self, &mut self.current_id);
|
||||
|
||||
let mut desc = pass.desc(self);
|
||||
|
||||
for slot in &mut desc.slots {
|
||||
if let Some((id, other)) = self.slot_names.get(&slot.name)
|
||||
if let Some((id, other)) = self
|
||||
.slot_names
|
||||
.get(&slot.name)
|
||||
.and_then(|id| self.slots.get_mut(id).map(|s| (id, s)))
|
||||
{
|
||||
slot.id = *id;
|
||||
|
||||
if slot.desc.is_some() && other.create_desc.is_none() {
|
||||
other.create_desc = slot.desc;
|
||||
other.create_desc = slot.desc.clone();
|
||||
}
|
||||
} else {
|
||||
let res_slot = ResourcedSlot {
|
||||
name: slot.name,
|
||||
name: slot.name.clone(),
|
||||
ty: slot.ty,
|
||||
value: SlotValue::None,
|
||||
bind_group_id: None,
|
||||
create_desc: slot.desc,
|
||||
create_desc: slot.desc.clone(),
|
||||
};
|
||||
|
||||
self.slots.insert(slot.id, res_slot);
|
||||
self.slot_names.insert(slot.name, slot.id);
|
||||
self.slot_names.insert(slot.name.clone(), slot.id);
|
||||
}
|
||||
}
|
||||
|
||||
self.passes.insert(desc.id, PassEntry {
|
||||
inner: Box::new(pass),
|
||||
desc,
|
||||
});
|
||||
|
||||
self.passes.insert(
|
||||
desc.id,
|
||||
PassEntry {
|
||||
inner: Arc::new(RefCell::new(pass)),
|
||||
desc,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Creates all buffers required for the passes, also creates an internal execution path.
|
||||
#[instrument(skip(self, device))]
|
||||
pub fn setup(&mut self, device: &wgpu::Device) {
|
||||
let mut later_slots = VecDeque::new();
|
||||
|
||||
for slot in self.slots.values_mut() {
|
||||
if slot.bind_group_id.is_none() {
|
||||
match slot.create_desc {
|
||||
// For all passes, create their pipelines
|
||||
for pass in self.passes.values() {
|
||||
if let Some(pipei) = &pass.desc.pipeline_info {
|
||||
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![]))
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
|
||||
let res = PipelineResource {
|
||||
pipeline,
|
||||
bg_layout_name_lookup: Default::default(),
|
||||
};
|
||||
self.pipelines.insert(pass.desc.id, res);
|
||||
}
|
||||
}
|
||||
|
||||
for (slot_id, slot) in &mut self.slots {
|
||||
if slot.bind_group_id.is_none() && slot.create_desc.is_some() {
|
||||
let s = debug_span!("res_creation", slot = slot.name);
|
||||
let _e = s.enter();
|
||||
|
||||
debug!("Creating bind group for slot");
|
||||
|
||||
match &slot.create_desc {
|
||||
Some(SlotDescriptor::BufferInit(bi)) => {
|
||||
let label = format!("B_{}", slot.name);
|
||||
let wb = bi.as_wgpu(Some(&label));
|
||||
|
@ -127,98 +197,125 @@ impl RenderGraph {
|
|||
let buf = device.create_buffer_init(&wb);
|
||||
slot.value = SlotValue::Buffer(buf);
|
||||
|
||||
debug!(slot=slot.name, "Created and initialized buffer for slot");
|
||||
},
|
||||
debug!("Created and initialized buffer for slot");
|
||||
}
|
||||
Some(SlotDescriptor::Buffer(b)) => {
|
||||
let label = format!("B_{}", slot.name);
|
||||
let wb = b.as_wgpu(Some(&label));
|
||||
|
||||
|
||||
let buf = device.create_buffer(&wb);
|
||||
slot.value = SlotValue::Buffer(buf);
|
||||
|
||||
debug!(slot=slot.name, "Created buffer");
|
||||
debug!("Created buffer");
|
||||
}
|
||||
Some(SlotDescriptor::Texture(t)) => {
|
||||
let label = format!("Tex_{}", slot.name);
|
||||
let wt = t.as_wgpu(Some(&label));
|
||||
|
||||
let tex = device.create_texture(&wt);
|
||||
slot.value = SlotValue::Texture(tex);
|
||||
|
||||
debug!("Created texture");
|
||||
}
|
||||
Some(SlotDescriptor::TextureView(tv)) => {
|
||||
// texture views cannot be done in this step. Not only would we run into a
|
||||
// borrow checker error when trying to get the texture for the view, we
|
||||
// can also not guarantee that the texture was actually created.
|
||||
let tex_slot = self
|
||||
.slot_names
|
||||
.get(&tv.texture_label)
|
||||
.expect("Failed to find texture for texture view slot");
|
||||
later_slots.push_back((*slot_id, *tex_slot));
|
||||
|
||||
debug!("Queuing slot resources for later creation");
|
||||
}
|
||||
|
||||
//Some(SlotDescriptor::Sampler(b)) => {},
|
||||
//Some(SlotDescriptor::Texture(b)) => {},
|
||||
//Some(SlotDescriptor::TextureView(b)) => {},
|
||||
Some(SlotDescriptor::None) => {},
|
||||
None => {},
|
||||
Some(SlotDescriptor::None) => {}
|
||||
None => {}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
todo!()
|
||||
// create buffers for the queued slots
|
||||
while let Some((lower_id, upper_id)) = later_slots.pop_front() {
|
||||
let many = self.slots.get_many_mut([&lower_id, &upper_id]).unwrap();
|
||||
let (lower_slot, upper_slot) = match many {
|
||||
[a, b] => (a, b),
|
||||
};
|
||||
|
||||
let s = debug_span!("deferred_res_creation", slot = lower_slot.name);
|
||||
let _e = s.enter();
|
||||
|
||||
match &lower_slot.create_desc {
|
||||
Some(SlotDescriptor::TextureView(tv)) => {
|
||||
let label = format!("TexView_{}", lower_slot.name);
|
||||
|
||||
let wt = tv.as_wgpu(Some(&label));
|
||||
let tex = upper_slot.value.as_texture();
|
||||
|
||||
let texview = tex.create_view(&wt);
|
||||
lower_slot.value = SlotValue::TextureView(texview);
|
||||
|
||||
debug!(slot = lower_slot.name, "Created texture view");
|
||||
}
|
||||
Some(SlotDescriptor::None) => {}
|
||||
None => {}
|
||||
_ => unreachable!("this slot should not have been put into the do later list"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn prepare(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn render(&mut self, renderer: &mut BasicRenderer) {
|
||||
todo!()
|
||||
let builtin = {
|
||||
let mut h = FxHashSet::default();
|
||||
h.insert(0u64);
|
||||
h
|
||||
};
|
||||
let descs = self.passes.values().map(|p| &p.desc).collect();
|
||||
self.exec_path = Some(GraphExecutionPath::new(builtin, descs));
|
||||
}
|
||||
|
||||
/// Get a pipeline by name from the graph.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the pipeline was not found by name.
|
||||
#[inline(always)]
|
||||
pub fn pipeline(&self, name: &str) -> &Pipeline {
|
||||
&self.pipelines.get(name)
|
||||
.unwrap()
|
||||
.pipeline
|
||||
pub fn render(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, surface: &wgpu::Surface) {
|
||||
let mut path = self.exec_path.take().unwrap();
|
||||
|
||||
let output = surface.get_current_texture().unwrap();
|
||||
let view = output
|
||||
.texture
|
||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||
|
||||
// update the window texture view slot.
|
||||
let window_tv_slot = self.slots.get_mut(&0).unwrap(); // 0 is window_texture_view
|
||||
debug_assert_eq!(
|
||||
window_tv_slot.name.as_str(),
|
||||
"window_texture_view",
|
||||
"unexpected slot where 'window_texture_view' should be"
|
||||
);
|
||||
window_tv_slot.value = SlotValue::TextureView(view);
|
||||
|
||||
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 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);
|
||||
|
||||
queue.submit(std::iter::once(context.encoder.finish()));
|
||||
}
|
||||
|
||||
output.present();
|
||||
}
|
||||
|
||||
/// Attempt to get a pipeline by name from the graph.
|
||||
///
|
||||
/// Returns `None` if the pipeline was not found by name,
|
||||
#[inline(always)]
|
||||
pub fn try_pipeline(&self, name: &str) -> Option<&Pipeline> {
|
||||
self.pipelines.get(name)
|
||||
.map(|p| &p.pipeline)
|
||||
}
|
||||
|
||||
/// Get a [`RenderPipeline`] by name from the graph.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the pipeline was not found by name, or if the pipeline is not a render pipeline.
|
||||
#[inline(always)]
|
||||
pub fn render_pipeline(&self, name: &str) -> &RenderPipeline {
|
||||
self.pipelines.get(name)
|
||||
.unwrap()
|
||||
.pipeline
|
||||
.as_render()
|
||||
}
|
||||
|
||||
/// Attempt to get a [`RenderPipeline`] by name from the graph.
|
||||
///
|
||||
/// Returns `None` if the pipeline was not found by name, or if the pipeline is not a render pipeline.
|
||||
#[inline(always)]
|
||||
pub fn try_render_pipeline(&self, name: &str) -> Option<&RenderPipeline> {
|
||||
self.pipelines.get(name)
|
||||
.and_then(|p| p.pipeline.try_as_render())
|
||||
}
|
||||
|
||||
/// Get a [`ComputePipeline`] by name from the graph.
|
||||
///
|
||||
/// # Panics
|
||||
/// Panics if the pipeline was not found by name, or if the pipeline is not a compute pipeline.
|
||||
#[inline(always)]
|
||||
pub fn compute_pipeline(&self, name: &str) -> &ComputePipeline {
|
||||
&self.pipelines.get(name)
|
||||
.unwrap()
|
||||
.pipeline
|
||||
.as_compute()
|
||||
}
|
||||
|
||||
/// Attempt to get a [`ComputePipeline`] by name from the graph.
|
||||
///
|
||||
/// Returns `None` if the pipeline was not found by name, or if the pipeline is not a render pipeline.
|
||||
#[inline(always)]
|
||||
pub fn try_compute_pipeline(&self, name: &str) -> Option<&ComputePipeline> {
|
||||
self.pipelines.get(name)
|
||||
.and_then(|p| p.pipeline.try_as_compute())
|
||||
pub fn pipeline(&self, id: u64) -> &Pipeline {
|
||||
&self.pipelines.get(&id).unwrap().pipeline
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
@ -228,19 +325,24 @@ impl RenderGraph {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn bind_group(&self, id: u64) -> &wgpu::BindGroup {
|
||||
self.try_bind_group(id)
|
||||
.expect("Unknown id for bind group")
|
||||
self.try_bind_group(id).expect("Unknown id for bind group")
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn try_slot_bind_group(&self, id: u64) -> Option<&wgpu::BindGroup> {
|
||||
self.slots.get(&id)
|
||||
.and_then(|s| self.bind_groups.get(&s.bind_group_id.expect("Slot bind group has not been created yet")))
|
||||
self.slots.get(&id).and_then(|s| {
|
||||
self.bind_groups.get(
|
||||
&s.bind_group_id
|
||||
.expect("Slot bind group has not been created yet"),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn slot_bind_group(&self, id: u64) -> &wgpu::BindGroup {
|
||||
let bg_id = self.slots.get(&id)
|
||||
let bg_id = self
|
||||
.slots
|
||||
.get(&id)
|
||||
.expect("unknown slot id")
|
||||
.bind_group_id
|
||||
.expect("Slot bind group has not been created yet");
|
||||
|
@ -248,17 +350,50 @@ impl RenderGraph {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct BufferWrite {
|
||||
/// The name of the slot that has the resource that will be written
|
||||
target_slot: String,
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct RenderGraphContext<'a> {
|
||||
encoder: wgpu::CommandEncoder,
|
||||
queue: &'a wgpu::Queue,
|
||||
/// Becomes None when the encoder is submitted
|
||||
pub(crate) encoder: wgpu::CommandEncoder,
|
||||
pub(crate) queue: &'a wgpu::Queue,
|
||||
pub(crate) buffer_writes: Vec<BufferWrite>,
|
||||
renderpass_desc: Vec<wgpu::RenderPassDescriptor<'a, 'a>>,
|
||||
}
|
||||
|
||||
impl<'a> RenderGraphContext<'a> {
|
||||
pub fn begin_render_pass(&mut self, desc: &wgpu::RenderPassDescriptor) -> wgpu::RenderPass {
|
||||
todo!()
|
||||
pub fn new(encoder: wgpu::CommandEncoder, queue: &'a wgpu::Queue) -> Self {
|
||||
Self {
|
||||
encoder,
|
||||
queue,
|
||||
buffer_writes: vec![],
|
||||
renderpass_desc: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn begin_render_pass(
|
||||
&'a mut self,
|
||||
desc: wgpu::RenderPassDescriptor<'a, 'a>,
|
||||
) -> wgpu::RenderPass {
|
||||
self.encoder.begin_render_pass(&desc)
|
||||
}
|
||||
|
||||
pub fn begin_compute_pass(&mut self, desc: &wgpu::ComputePassDescriptor) -> wgpu::ComputePass {
|
||||
todo!()
|
||||
self.encoder.begin_compute_pass(desc)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_buffer(&mut self, target_slot: &str, bytes: &[u8]) {
|
||||
//self.queue.write_buffer(buffer, offset, data)
|
||||
self.buffer_writes.push(BufferWrite {
|
||||
target_slot: target_slot.to_string(),
|
||||
bytes: bytes.to_vec(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write_buffer_muck<T: bytemuck::NoUninit>(&mut self, target_slot: &str, bytes: T) {
|
||||
self.write_buffer(target_slot, bytemuck::bytes_of(&bytes));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,23 @@ pub enum SlotValue {
|
|||
Buffer(wgpu::Buffer),
|
||||
}
|
||||
|
||||
impl SlotValue {
|
||||
/// Gets `self` as a texture, panics if self is not a instance of [`SlotValue::Texture`].
|
||||
pub fn as_texture(&self) -> &wgpu::Texture {
|
||||
match self {
|
||||
Self::Texture(t) => t,
|
||||
_ => panic!("self is not an instance of SlotValue::Texture"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_texture_view(&self) -> &wgpu::TextureView {
|
||||
match self {
|
||||
Self::TextureView(t) => t,
|
||||
_ => panic!("self is not an instance of SlotValue::TextureView"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SlotDescriptor {
|
||||
/// Most likely this slot is an input, so it doesn't need to specify the descriptor.
|
||||
|
@ -57,6 +74,21 @@ pub struct RenderPassSlot {
|
|||
pub desc: Option<SlotDescriptor>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RenderGraphPipelineInfo {
|
||||
pub label: String,
|
||||
pub source: String,
|
||||
}
|
||||
|
||||
impl RenderGraphPipelineInfo {
|
||||
pub fn new(label: &str, source: &str) -> Self {
|
||||
Self {
|
||||
label: label.to_string(),
|
||||
source: source.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct RenderGraphPassDesc {
|
||||
pub id: u64,
|
||||
|
@ -64,16 +96,18 @@ pub struct RenderGraphPassDesc {
|
|||
pub pass_type: RenderPassType,
|
||||
pub slots: Vec<RenderPassSlot>,
|
||||
slot_names: HashMap<String, u64>,
|
||||
pub pipeline_info: Option<RenderGraphPipelineInfo>,
|
||||
}
|
||||
|
||||
impl RenderGraphPassDesc {
|
||||
pub fn new(id: u64, name: &str, pass_type: RenderPassType) -> Self {
|
||||
pub fn new(id: u64, name: &str, pass_type: RenderPassType, pipeline_info: Option<RenderGraphPipelineInfo>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
name: name.to_string(),
|
||||
pass_type,
|
||||
slots: vec![],
|
||||
slot_names: HashMap::default(),
|
||||
pipeline_info
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,7 +118,7 @@ impl RenderGraphPassDesc {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn add_buffer_slot(&mut self, id: u64, name: &str, attribute: SlotAttribute, desc: Option<SlotDescriptor>) {
|
||||
debug_assert!(matches!(desc, Some(SlotDescriptor::Buffer(_)) | Some(SlotDescriptor::BufferInit(_)) ),
|
||||
debug_assert!(matches!(desc, None | Some(SlotDescriptor::Buffer(_)) | Some(SlotDescriptor::BufferInit(_)) ),
|
||||
"slot descriptor does not match the type of slot");
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
|
@ -99,7 +133,7 @@ impl RenderGraphPassDesc {
|
|||
|
||||
#[inline(always)]
|
||||
pub fn add_texture_slot(&mut self, id: u64, name: &str, attribute: SlotAttribute, desc: Option<SlotDescriptor>) {
|
||||
debug_assert!(matches!(desc, Some(SlotDescriptor::Texture(_))),
|
||||
debug_assert!(matches!(desc, None | Some(SlotDescriptor::Texture(_))),
|
||||
"slot descriptor does not match the type of slot");
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
|
@ -114,7 +148,7 @@ 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, Some(SlotDescriptor::TextureView(_))),
|
||||
debug_assert!(matches!(desc, None | Some(SlotDescriptor::TextureView(_))),
|
||||
"slot descriptor does not match the type of slot");
|
||||
|
||||
let slot = RenderPassSlot {
|
||||
|
@ -128,8 +162,8 @@ impl RenderGraphPassDesc {
|
|||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn add_texture_sampler_slot(&mut self, id: u64, name: &str, attribute: SlotAttribute, desc: Option<SlotDescriptor>) {
|
||||
debug_assert!(matches!(desc, Some(SlotDescriptor::Sampler(_))),
|
||||
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 {
|
||||
|
@ -161,8 +195,8 @@ pub trait RenderGraphPass: 'static {
|
|||
/// Create a render pass describer.
|
||||
///
|
||||
/// The `id` argument is passed as mutable so you can increment it as you use it for new slots.
|
||||
fn desc(&self, graph: &mut RenderGraph, id: &mut u64) -> RenderGraphPassDesc;
|
||||
fn desc<'a, 'b>(&'a self, graph: &'b mut RenderGraph) -> RenderGraphPassDesc;
|
||||
|
||||
fn prepare(&mut self, world: &mut World);
|
||||
fn prepare(&mut self, world: &mut World, context: &mut RenderGraphContext);
|
||||
fn execute(&mut self, graph: &mut RenderGraph, desc: &RenderGraphPassDesc, context: &mut RenderGraphContext);
|
||||
}
|
|
@ -1,8 +1,14 @@
|
|||
mod light_cull_compute;
|
||||
/* mod light_cull_compute;
|
||||
pub use light_cull_compute::*;
|
||||
|
||||
mod base;
|
||||
pub use base::*;
|
||||
|
||||
mod depth_prepass;
|
||||
pub use depth_prepass::*;
|
||||
pub use depth_prepass::*;
|
||||
|
||||
mod simple_phong;
|
||||
pub use simple_phong::*; */
|
||||
|
||||
mod triangle;
|
||||
pub use triangle::*;
|
|
@ -0,0 +1,95 @@
|
|||
use glam::UVec2;
|
||||
use tracing::warn;
|
||||
|
||||
use crate::{
|
||||
render::{
|
||||
camera::{CameraUniform, RenderCamera},
|
||||
graph::{
|
||||
BufferInitDescriptor, RenderGraphContext, RenderGraphPass, RenderGraphPassDesc,
|
||||
RenderGraphPipelineInfo, RenderPassType, SlotAttribute, SlotDescriptor,
|
||||
},
|
||||
renderer::ScreenSize,
|
||||
},
|
||||
scene::CameraComponent,
|
||||
};
|
||||
|
||||
/// Supplies some basic things other passes needs.
|
||||
///
|
||||
/// screen size buffer, camera buffer,
|
||||
#[derive(Default)]
|
||||
pub struct TrianglePass;
|
||||
|
||||
impl TrianglePass {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderGraphPass for TrianglePass {
|
||||
fn desc(
|
||||
&self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
) -> crate::render::graph::RenderGraphPassDesc {
|
||||
let mut desc = RenderGraphPassDesc::new(
|
||||
graph.next_id(),
|
||||
"TrianglePass",
|
||||
RenderPassType::Render,
|
||||
Some(RenderGraphPipelineInfo::new(
|
||||
"TriangleShader",
|
||||
include_str!("../../shaders/triangle.wgsl"),
|
||||
)),
|
||||
);
|
||||
|
||||
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()),
|
||||
contents: bytemuck::bytes_of(&UVec2::new(800, 600)).to_vec(),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
})));
|
||||
desc.add_buffer_slot(graph.next_id(), "camera_buffer", SlotAttribute::Output, Some(SlotDescriptor::BufferInit(BufferInitDescriptor {
|
||||
label: Some("B_Camera".to_string()),
|
||||
contents: bytemuck::bytes_of(&CameraUniform::default()).to_vec(),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
}))); */
|
||||
|
||||
desc
|
||||
}
|
||||
|
||||
fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {}
|
||||
|
||||
fn execute(
|
||||
&mut self,
|
||||
graph: &mut crate::render::graph::RenderGraph,
|
||||
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 encoder = &mut context.encoder;
|
||||
|
||||
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("TrianglePass"),
|
||||
color_attachments: &[
|
||||
// This is what @location(0) in the fragment shader targets
|
||||
Some(wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
resolve_target: None,
|
||||
ops: wgpu::Operations {
|
||||
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||
r: 0.1,
|
||||
g: 0.2,
|
||||
b: 0.3,
|
||||
a: 1.0,
|
||||
}),
|
||||
store: true,
|
||||
},
|
||||
}),
|
||||
],
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
let pipeline = graph.pipeline(desc.id);
|
||||
pass.set_pipeline(&pipeline.as_render());
|
||||
pass.draw(0..3, 0..1);
|
||||
}
|
||||
}
|
|
@ -40,6 +40,19 @@ impl TextureViewDescriptor {
|
|||
array_layer_count: d.array_layer_count,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_wgpu<'a>(&self, label: Option<&'a str>) -> wgpu::TextureViewDescriptor<'a> {
|
||||
wgpu::TextureViewDescriptor {
|
||||
label,
|
||||
format: self.format,
|
||||
dimension: self.dimension,
|
||||
aspect: self.aspect,
|
||||
base_mip_level: self.base_mip_level,
|
||||
mip_level_count: self.mip_level_count,
|
||||
base_array_layer: self.base_array_layer,
|
||||
array_layer_count: self.array_layer_count,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -117,6 +130,21 @@ pub struct TextureDescriptor {
|
|||
pub view_formats: Vec<wgpu::TextureFormat>,
|
||||
}
|
||||
|
||||
impl TextureDescriptor {
|
||||
pub fn as_wgpu<'a>(&'a self, label: Option<&'a str>) -> wgpu::TextureDescriptor<'a> {
|
||||
wgpu::TextureDescriptor {
|
||||
label,
|
||||
size: self.size,
|
||||
mip_level_count: self.mip_level_count,
|
||||
sample_count: self.sample_count,
|
||||
dimension: self.dimension,
|
||||
format: self.format,
|
||||
usage: self.usage,
|
||||
view_formats: &self.view_formats,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct BufferDescriptor {
|
||||
|
@ -134,7 +162,7 @@ pub struct BufferDescriptor {
|
|||
}
|
||||
|
||||
impl BufferDescriptor {
|
||||
pub fn as_wgpu(&self, label: Option<&str>) -> wgpu::BufferDescriptor {
|
||||
pub fn as_wgpu<'a>(&self, label: Option<&'a str>) -> wgpu::BufferDescriptor<'a> {
|
||||
wgpu::BufferDescriptor {
|
||||
label,
|
||||
size: self.size,
|
||||
|
@ -156,7 +184,7 @@ pub struct BufferInitDescriptor {
|
|||
}
|
||||
|
||||
impl BufferInitDescriptor {
|
||||
pub fn as_wgpu(&self, label: Option<&str>) -> wgpu::util::BufferInitDescriptor {
|
||||
pub fn as_wgpu<'a>(&'a self, label: Option<&'a str>) -> wgpu::util::BufferInitDescriptor<'a> {
|
||||
wgpu::util::BufferInitDescriptor {
|
||||
label,
|
||||
contents: &self.contents,
|
||||
|
|
|
@ -56,13 +56,14 @@ impl RenderPipeline {
|
|||
// Requires Features::CONSERVATIVE_RASTERIZATION
|
||||
conservative: false,
|
||||
},
|
||||
depth_stencil: Some(wgpu::DepthStencilState {
|
||||
/*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,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use std::collections::{VecDeque, HashSet};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::borrow::Cow;
|
||||
|
@ -18,7 +19,7 @@ use wgpu::util::DeviceExt;
|
|||
use winit::window::Window;
|
||||
|
||||
use crate::math::Transform;
|
||||
use crate::render::graph::{BasePass, DepthPrePass, LightCullComputePass};
|
||||
use crate::render::graph::TrianglePass;
|
||||
use crate::render::material::MaterialUniform;
|
||||
use crate::render::render_buffer::BufferWrapperBuilder;
|
||||
use crate::scene::CameraComponent;
|
||||
|
@ -44,6 +45,20 @@ type SceneHandle = ResHandle<SceneGraph>;
|
|||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct ScreenSize(glam::UVec2);
|
||||
|
||||
impl Deref for ScreenSize {
|
||||
type Target = glam::UVec2;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for ScreenSize {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Renderer {
|
||||
fn prepare(&mut self, main_world: &mut World);
|
||||
fn render(&mut self) -> Result<(), wgpu::SurfaceError>;
|
||||
|
@ -212,9 +227,15 @@ impl BasicRenderer {
|
|||
//let light_cull_compute = LightCullCompute::new(device.clone(), queue.clone(), size, &light_uniform_buffers, &camera_buffer, &mut depth_texture);
|
||||
|
||||
let mut g = RenderGraph::new(config.clone());
|
||||
g.add_pass(BasePass::new());
|
||||
/* debug!("Adding base pass");
|
||||
g.add_pass(TrianglePass::new());
|
||||
debug!("Adding depth pre-pass");
|
||||
g.add_pass(DepthPrePass::new());
|
||||
g.add_pass(LightCullComputePass::new(size));
|
||||
debug!("Adding light cull compute pass");
|
||||
g.add_pass(LightCullComputePass::new(size)); */
|
||||
|
||||
debug!("Adding triangle pass");
|
||||
g.add_pass(TrianglePass::new());
|
||||
g.setup(&device);
|
||||
|
||||
let mut s = Self {
|
||||
|
@ -261,7 +282,7 @@ impl Renderer for BasicRenderer {
|
|||
|
||||
#[instrument(skip(self))]
|
||||
fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
|
||||
self.graph.render(self);
|
||||
self.graph.render(&self.device, &self.queue, &self.surface);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -276,7 +297,7 @@ impl Renderer for BasicRenderer {
|
|||
// tell other things of updated resize
|
||||
self.surface.configure(&self.device, &self.config);
|
||||
|
||||
let mut world_ss = world.get_resource::<ScreenSize>();
|
||||
let mut world_ss = world.get_resource_mut::<ScreenSize>();
|
||||
world_ss.0 = glam::UVec2::new(new_size.width, new_size.height);
|
||||
self.graph.surface_config = self.config.clone();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
struct VertexOutput {
|
||||
@builtin(position) clip_position: vec4<f32>,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn vs_main(
|
||||
@builtin(vertex_index) in_vertex_index: u32,
|
||||
) -> VertexOutput {
|
||||
var out: VertexOutput;
|
||||
let x = f32(1 - i32(in_vertex_index)) * 0.5;
|
||||
let y = f32(i32(in_vertex_index & 1u) * 2 - 1) * 0.5;
|
||||
out.clip_position = vec4<f32>(x, y, 0.0, 1.0);
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
return vec4<f32>(0.3, 0.2, 0.1, 1.0);
|
||||
}
|
Loading…
Reference in New Issue