render: create ViewTarget to make it easier to render to a non-surface texture and chain together postprocess steps
This commit is contained in:
parent
0e71c5734f
commit
545da71cda
|
@ -2,7 +2,7 @@ use std::{collections::VecDeque, sync::Arc};
|
||||||
|
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
use super::{Frame, RenderGraphLabel, RenderGraphLabelValue, RenderTarget};
|
use super::{RenderGraphLabel, RenderGraphLabelValue};
|
||||||
|
|
||||||
/// A queued write to a GPU buffer targeting a graph slot.
|
/// A queued write to a GPU buffer targeting a graph slot.
|
||||||
pub(crate) struct GraphBufferWrite {
|
pub(crate) struct GraphBufferWrite {
|
||||||
|
@ -86,4 +86,16 @@ impl<'a> RenderGraphContext<'a> {
|
||||||
) {
|
) {
|
||||||
self.queue_buffer_write(target_slot, offset, bytemuck::bytes_of(&bytes));
|
self.queue_buffer_write(target_slot, offset, bytemuck::bytes_of(&bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Submit the encoder to the gpu queue.
|
||||||
|
///
|
||||||
|
/// The `encoder` of this context will be `None` until the next node is executed, then another
|
||||||
|
/// one will be made. You likely don't need to run this yourself until you are manually
|
||||||
|
/// presenting a surface texture.
|
||||||
|
pub fn submit_encoder(&mut self) {
|
||||||
|
let en = self.encoder.take()
|
||||||
|
.unwrap()
|
||||||
|
.finish();
|
||||||
|
self.queue.submit(std::iter::once(en));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
mod node;
|
mod node;
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell}, collections::{HashMap, VecDeque}, fmt::Debug, hash::Hash, rc::Rc, sync::Arc
|
cell::{Ref, RefCell, RefMut}, collections::{HashMap, VecDeque}, fmt::Debug, hash::Hash, rc::Rc, sync::Arc
|
||||||
};
|
};
|
||||||
|
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::World;
|
||||||
|
@ -125,10 +125,11 @@ pub struct RenderGraph {
|
||||||
bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>,
|
bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>,
|
||||||
/// A directed graph used to determine dependencies of nodes.
|
/// A directed graph used to determine dependencies of nodes.
|
||||||
node_graph: petgraph::matrix_graph::DiMatrix<RenderGraphLabelValue, (), Option<()>, usize>,
|
node_graph: petgraph::matrix_graph::DiMatrix<RenderGraphLabelValue, (), Option<()>, usize>,
|
||||||
|
view_target: Rc<RefCell<ViewTarget>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RenderGraph {
|
impl RenderGraph {
|
||||||
pub fn new(device: Arc<wgpu::Device>, queue: Arc<wgpu::Queue>) -> Self {
|
pub fn new(device: Arc<wgpu::Device>, queue: Arc<wgpu::Queue>, view_target: Rc<RefCell<ViewTarget>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
device,
|
device,
|
||||||
queue,
|
queue,
|
||||||
|
@ -137,6 +138,7 @@ impl RenderGraph {
|
||||||
sub_graphs: Default::default(),
|
sub_graphs: Default::default(),
|
||||||
bind_groups: Default::default(),
|
bind_groups: Default::default(),
|
||||||
node_graph: Default::default(),
|
node_graph: Default::default(),
|
||||||
|
view_target,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,28 +346,18 @@ impl RenderGraph {
|
||||||
let device = self.device.clone();
|
let device = self.device.clone();
|
||||||
let queue = self.queue.clone();
|
let queue = self.queue.clone();
|
||||||
|
|
||||||
// create a new encoder since the last one was presented
|
// create a new encoder if the last one was submitted
|
||||||
if encoder.is_none() {
|
if encoder.is_none() {
|
||||||
encoder = Some(self.create_encoder());
|
encoder = Some(self.create_encoder());
|
||||||
}
|
}
|
||||||
|
|
||||||
// all encoders need to be submitted before a presenter node is executed.
|
|
||||||
if pass_desc.ty == NodeType::Presenter {
|
|
||||||
trace!("Submitting encoder before presenting");
|
|
||||||
|
|
||||||
let finished = encoder.take().unwrap().finish();
|
|
||||||
self.queue.submit(std::iter::once(finished));
|
|
||||||
|
|
||||||
// Do not create a new encoder yet since this node may be the last node.
|
|
||||||
// A new encoder can be made on the next iteration of this loop.
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut context = RenderGraphContext::new(device, queue, encoder.take(), pass_label.clone());
|
let mut context = RenderGraphContext::new(device, queue, encoder.take(), pass_label.clone());
|
||||||
|
|
||||||
trace!("Executing {:?}", pass_label.0);
|
trace!("Executing {:?}", pass_label.0);
|
||||||
let mut inner = pass_inn.borrow_mut();
|
let mut inner = pass_inn.borrow_mut();
|
||||||
inner.execute(self, &pass_desc, &mut context);
|
inner.execute(self, &pass_desc, &mut context);
|
||||||
|
|
||||||
|
// take back the encoder from the context
|
||||||
encoder = context.encoder;
|
encoder = context.encoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,6 +523,14 @@ impl RenderGraph {
|
||||||
sg.bind_groups.insert(bg.label.clone(), bg);
|
sg.bind_groups.insert(bg.label.clone(), bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn view_target(&self) -> Ref<ViewTarget> {
|
||||||
|
self.view_target.borrow()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view_target_mut(&self) -> RefMut<ViewTarget> {
|
||||||
|
self.view_target.borrow_mut()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SubGraphNode {
|
pub struct SubGraphNode {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{cell::RefCell, rc::Rc};
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use glam::UVec2;
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
use lyra_game_derive::RenderGraphLabel;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use winit::dpi::PhysicalSize;
|
use winit::dpi::PhysicalSize;
|
||||||
|
@ -8,7 +9,7 @@ use crate::{
|
||||||
render::{
|
render::{
|
||||||
camera::{CameraUniform, RenderCamera},
|
camera::{CameraUniform, RenderCamera},
|
||||||
graph::{
|
graph::{
|
||||||
Node, NodeDesc, NodeSlot, NodeType, RenderGraph, RenderGraphContext, RenderTarget, SlotAttribute, SlotType, SlotValue
|
Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue
|
||||||
},
|
},
|
||||||
render_buffer::BufferWrapper, texture::RenderTexture,
|
render_buffer::BufferWrapper, texture::RenderTexture,
|
||||||
},
|
},
|
||||||
|
@ -23,10 +24,7 @@ pub enum BasePassSlots {
|
||||||
DepthTexture,
|
DepthTexture,
|
||||||
ScreenSize,
|
ScreenSize,
|
||||||
Camera,
|
Camera,
|
||||||
MainRenderTarget,
|
|
||||||
WindowTextureView,
|
|
||||||
DepthTextureView,
|
DepthTextureView,
|
||||||
Frame,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Supplies some basic things other passes needs.
|
/// Supplies some basic things other passes needs.
|
||||||
|
@ -34,23 +32,12 @@ pub enum BasePassSlots {
|
||||||
/// screen size buffer, camera buffer,
|
/// screen size buffer, camera buffer,
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct BasePass {
|
pub struct BasePass {
|
||||||
/// Temporary storage for the main render target
|
screen_size: UVec2,
|
||||||
///
|
|
||||||
/// This should be Some when the pass is first created then after its added to
|
|
||||||
/// the render graph it will be None and stay None.
|
|
||||||
temp_render_target: Option<RenderTarget>,
|
|
||||||
screen_size: glam::UVec2,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasePass {
|
impl BasePass {
|
||||||
pub fn new(render_target: RenderTarget) -> Self {
|
pub fn new() -> Self {
|
||||||
let size = render_target.size();
|
Self::default()
|
||||||
|
|
||||||
Self {
|
|
||||||
temp_render_target: Some(render_target),
|
|
||||||
screen_size: size,
|
|
||||||
..Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +46,8 @@ impl Node for BasePass {
|
||||||
&mut self,
|
&mut self,
|
||||||
graph: &mut crate::render::graph::RenderGraph,
|
graph: &mut crate::render::graph::RenderGraph,
|
||||||
) -> crate::render::graph::NodeDesc {
|
) -> crate::render::graph::NodeDesc {
|
||||||
let render_target = self.temp_render_target.take().unwrap();
|
let vt = graph.view_target();
|
||||||
self.screen_size = render_target.size();
|
self.screen_size = vt.size();
|
||||||
|
|
||||||
let (screen_size_bgl, screen_size_bg, screen_size_buf, _) = BufferWrapper::builder()
|
let (screen_size_bgl, screen_size_bg, screen_size_buf, _) = BufferWrapper::builder()
|
||||||
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
|
.buffer_usage(wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST)
|
||||||
|
@ -107,25 +94,6 @@ impl Node for BasePass {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
desc.add_slot(NodeSlot {
|
|
||||||
ty: SlotType::RenderTarget,
|
|
||||||
attribute: SlotAttribute::Output,
|
|
||||||
label: BasePassSlots::MainRenderTarget.into(),
|
|
||||||
value: Some(SlotValue::RenderTarget(Rc::new(RefCell::new(
|
|
||||||
render_target,
|
|
||||||
)))),
|
|
||||||
});
|
|
||||||
desc.add_slot(NodeSlot {
|
|
||||||
ty: SlotType::Frame,
|
|
||||||
attribute: SlotAttribute::Output,
|
|
||||||
label: BasePassSlots::Frame.into(),
|
|
||||||
value: Some(SlotValue::Lazy),
|
|
||||||
});
|
|
||||||
desc.add_texture_view_slot(
|
|
||||||
BasePassSlots::WindowTextureView,
|
|
||||||
SlotAttribute::Output,
|
|
||||||
Some(SlotValue::Lazy),
|
|
||||||
);
|
|
||||||
desc.add_texture_view_slot(
|
desc.add_texture_view_slot(
|
||||||
BasePassSlots::DepthTextureView,
|
BasePassSlots::DepthTextureView,
|
||||||
SlotAttribute::Output,
|
SlotAttribute::Output,
|
||||||
|
@ -145,10 +113,12 @@ impl Node for BasePass {
|
||||||
desc
|
desc
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
|
fn prepare(&mut self, graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) {
|
||||||
if let Some(camera) = world.view_iter::<&mut CameraComponent>().next() {
|
if let Some(camera) = world.view_iter::<&mut CameraComponent>().next() {
|
||||||
|
let screen_size = graph.view_target().size();
|
||||||
|
|
||||||
let mut render_cam =
|
let mut render_cam =
|
||||||
RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y));
|
RenderCamera::new(PhysicalSize::new(screen_size.x, screen_size.y));
|
||||||
let uniform = render_cam.calc_view_projection(&camera);
|
let uniform = render_cam.calc_view_projection(&camera);
|
||||||
|
|
||||||
context.queue_buffer_write_with(BasePassSlots::Camera, 0, uniform)
|
context.queue_buffer_write_with(BasePassSlots::Camera, 0, uniform)
|
||||||
|
@ -163,38 +133,20 @@ impl Node for BasePass {
|
||||||
_desc: &crate::render::graph::NodeDesc,
|
_desc: &crate::render::graph::NodeDesc,
|
||||||
context: &mut crate::render::graph::RenderGraphContext,
|
context: &mut crate::render::graph::RenderGraphContext,
|
||||||
) {
|
) {
|
||||||
let tv_slot = graph
|
let mut vt = graph.view_target_mut();
|
||||||
.slot_value_mut(BasePassSlots::MainRenderTarget)
|
vt.primary.create_frame();
|
||||||
.expect("somehow the main render target slot is missing");
|
vt.next_chain(context.encoder.as_mut().unwrap());
|
||||||
let rt = tv_slot.as_render_target().unwrap();
|
vt.primary.create_frame_view();
|
||||||
let rt_size = rt.size();
|
|
||||||
let frame = rt.create_frame();
|
|
||||||
/* debug_assert!(
|
/* debug_assert!(
|
||||||
!rt.current_texture.is_some(),
|
!rt.current_texture.is_some(),
|
||||||
"main render target surface was not presented!"
|
"main render target surface was not presented!"
|
||||||
); */
|
); */
|
||||||
|
|
||||||
// update the screen size buffer if the size changed.
|
// update the screen size buffer if the size changed.
|
||||||
|
let rt_size = vt.size();
|
||||||
if rt_size != self.screen_size {
|
if rt_size != self.screen_size {
|
||||||
self.screen_size = rt_size;
|
self.screen_size = rt_size;
|
||||||
context.queue_buffer_write_with(BasePassSlots::ScreenSize, 0, self.screen_size)
|
context.queue_buffer_write_with(BasePassSlots::ScreenSize, 0, self.screen_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
let surface_tex = frame.texture();
|
|
||||||
let view = surface_tex
|
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
|
||||||
|
|
||||||
drop(rt); // must be manually dropped for borrow checker when getting texture view slot
|
|
||||||
|
|
||||||
let frame_slot = graph
|
|
||||||
.slot_value_mut(BasePassSlots::Frame)
|
|
||||||
.expect("somehow the frame slot is missing");
|
|
||||||
*frame_slot = SlotValue::Frame(Rc::new(RefCell::new(Some(frame))));
|
|
||||||
|
|
||||||
// store the surface texture to the slot
|
|
||||||
let tv_slot = graph
|
|
||||||
.slot_value_mut(BasePassSlots::WindowTextureView)
|
|
||||||
.expect("somehow the window texture view slot is missing");
|
|
||||||
*tv_slot = SlotValue::TextureView(Rc::new(view));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -440,12 +440,7 @@ impl Node for MeshPass {
|
||||||
|
|
||||||
if self.pipeline.is_none() {
|
if self.pipeline.is_none() {
|
||||||
let device = graph.device();
|
let device = graph.device();
|
||||||
|
let surface_config_format = graph.view_target().format();
|
||||||
let main_rt = graph.slot_value(BasePassSlots::MainRenderTarget)
|
|
||||||
.and_then(|s| s.as_render_target())
|
|
||||||
.expect("missing main render target");
|
|
||||||
let surface_config_format = main_rt.format();
|
|
||||||
drop(main_rt);
|
|
||||||
|
|
||||||
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
let camera_bgl = graph.bind_group_layout(BasePassSlots::Camera);
|
||||||
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
let lights_bgl = graph.bind_group_layout(LightBasePassSlots::Lights);
|
||||||
|
@ -508,11 +503,14 @@ impl Node for MeshPass {
|
||||||
) {
|
) {
|
||||||
let encoder = context.encoder.as_mut().unwrap();
|
let encoder = context.encoder.as_mut().unwrap();
|
||||||
|
|
||||||
let view = graph
|
/* let view = graph
|
||||||
.slot_value(BasePassSlots::WindowTextureView)
|
.slot_value(BasePassSlots::WindowTextureView)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_texture_view()
|
.as_texture_view()
|
||||||
.expect("BasePassSlots::WindowTextureView was not a TextureView slot");
|
.expect("BasePassSlots::WindowTextureView was not a TextureView slot"); */
|
||||||
|
|
||||||
|
let vt = graph.view_target();
|
||||||
|
let view = vt.render_view();
|
||||||
|
|
||||||
let depth_view = graph
|
let depth_view = graph
|
||||||
.slot_value(BasePassSlots::DepthTextureView)
|
.slot_value(BasePassSlots::DepthTextureView)
|
||||||
|
|
|
@ -16,5 +16,5 @@ pub use present_pass::*;
|
||||||
mod init;
|
mod init;
|
||||||
pub use init::*;
|
pub use init::*;
|
||||||
|
|
||||||
mod tint;
|
/* mod tint;
|
||||||
pub use tint::*;
|
pub use tint::*; */
|
|
@ -2,72 +2,42 @@ use std::hash::Hash;
|
||||||
|
|
||||||
use lyra_game_derive::RenderGraphLabel;
|
use lyra_game_derive::RenderGraphLabel;
|
||||||
|
|
||||||
use crate::render::graph::{Node, NodeDesc, NodeSlot, NodeType, RenderGraph, RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, SlotAttribute, SlotType};
|
use crate::render::graph::{Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
|
#[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
|
||||||
pub struct PresentPassLabel(RenderGraphLabelValue);
|
pub struct PresentPassLabel;
|
||||||
|
|
||||||
impl PresentPassLabel {
|
|
||||||
pub fn new(frame_label: impl RenderGraphLabel) -> Self {
|
|
||||||
Self(frame_label.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Supplies some basic things other passes needs.
|
/// Supplies some basic things other passes needs.
|
||||||
///
|
///
|
||||||
/// screen size buffer, camera buffer,
|
/// screen size buffer, camera buffer,
|
||||||
pub struct PresentPass {
|
#[derive(Default, Debug)]
|
||||||
/// Label of this pass
|
pub struct PresentPass;
|
||||||
pub label: PresentPassLabel,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PresentPass {
|
impl PresentPass {
|
||||||
/// Create a new PresentNode, presenting the frame at `frame_label`
|
pub fn new() -> Self {
|
||||||
pub fn new(frame_label: impl RenderGraphLabel) -> Self {
|
Self::default()
|
||||||
Self {
|
|
||||||
//render_target_slot: render_target_slot.rc_clone(),
|
|
||||||
label: PresentPassLabel::new(frame_label),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_node_label(present_pass_label: PresentPassLabel) -> Self {
|
|
||||||
Self {
|
|
||||||
label: present_pass_label,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node for PresentPass {
|
impl Node for PresentPass {
|
||||||
fn desc(&mut self, _graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::NodeDesc {
|
fn desc(&mut self, _graph: &mut crate::render::graph::RenderGraph) -> crate::render::graph::NodeDesc {
|
||||||
let mut desc = NodeDesc::new(
|
NodeDesc::new(
|
||||||
NodeType::Presenter,
|
NodeType::Presenter,
|
||||||
None,
|
None,
|
||||||
vec![],
|
vec![],
|
||||||
);
|
)
|
||||||
|
|
||||||
desc.add_slot(
|
|
||||||
NodeSlot {
|
|
||||||
ty: SlotType::Frame,
|
|
||||||
attribute: SlotAttribute::Input,
|
|
||||||
label: self.label.0.clone(),
|
|
||||||
value: None,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
desc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare(&mut self, _graph: &mut RenderGraph, _world: &mut lyra_ecs::World, _context: &mut RenderGraphContext) {
|
fn prepare(&mut self, _graph: &mut RenderGraph, _world: &mut lyra_ecs::World, _context: &mut RenderGraphContext) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(&mut self, graph: &mut crate::render::graph::RenderGraph, _desc: &crate::render::graph::NodeDesc, _context: &mut crate::render::graph::RenderGraphContext) {
|
fn execute(&mut self, graph: &mut crate::render::graph::RenderGraph, _desc: &crate::render::graph::NodeDesc, context: &mut crate::render::graph::RenderGraphContext) { let mut vt = graph.view_target_mut();
|
||||||
let slot = graph.slot_value_mut(self.label.0.clone())
|
vt.copy_to_primary(context.encoder.as_mut().unwrap());
|
||||||
.unwrap_or_else(|| panic!("frame slot '{:?}' for PresentPass is missing", self.label.0))
|
context.submit_encoder();
|
||||||
.as_frame_mut()
|
|
||||||
.unwrap()
|
let frame = vt.primary.frame.take()
|
||||||
.take()
|
.expect("ViewTarget.primary was already presented");
|
||||||
.unwrap_or_else(|| panic!("frame '{:?}' was already presented", self.label.0));
|
frame.present();
|
||||||
slot.present();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -39,7 +39,7 @@ impl RenderTarget {
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
dimension: wgpu::TextureDimension::D2,
|
dimension: wgpu::TextureDimension::D2,
|
||||||
format,
|
format,
|
||||||
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::COPY_SRC,
|
||||||
view_formats: &[],
|
view_formats: &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -142,4 +142,173 @@ impl Frame {
|
||||||
pub fn size(&self) -> math::UVec2 {
|
pub fn size(&self) -> math::UVec2 {
|
||||||
self.size
|
self.size
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stores the current frame, and the render target it came from.
|
||||||
|
pub struct FrameTarget {
|
||||||
|
pub render_target: RenderTarget,
|
||||||
|
/// None when a frame has not been created yet
|
||||||
|
pub frame: Option<Frame>,
|
||||||
|
/// The view to use to render to the frame.
|
||||||
|
pub frame_view: Option<wgpu::TextureView>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FrameTarget {
|
||||||
|
pub fn new(render_target: RenderTarget) -> Self {
|
||||||
|
Self {
|
||||||
|
render_target,
|
||||||
|
frame: None,
|
||||||
|
frame_view: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the size of the [`RenderTarget`].
|
||||||
|
pub fn size(&self) -> math::UVec2 {
|
||||||
|
self.render_target.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [`wgpu::TextureFormat`] of the [`RenderTarget`].
|
||||||
|
pub fn format(&self) -> wgpu::TextureFormat {
|
||||||
|
self.render_target.format()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create the frame using the inner [`RenderTarget`].
|
||||||
|
pub fn create_frame(&mut self) -> &mut Frame {
|
||||||
|
self.frame = Some(self.render_target.create_frame());
|
||||||
|
self.frame.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create the [`wgpu::TextureView`] for the [`Frame`], storing it in self and returning a reference to it.
|
||||||
|
pub fn create_frame_view(&mut self) -> &wgpu::TextureView {
|
||||||
|
let frame = self.frame.as_ref().expect("frame was not created, cannot create view");
|
||||||
|
|
||||||
|
self.frame_view = Some(frame.texture().create_view(&wgpu::TextureViewDescriptor::default()));
|
||||||
|
self.frame_view.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TargetViewChain {
|
||||||
|
source: FrameTarget,
|
||||||
|
dest: FrameTarget,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TargetViewChain {
|
||||||
|
pub fn next(&mut self, encoder: &mut wgpu::CommandEncoder) {
|
||||||
|
let size = self.source.size();
|
||||||
|
let size = wgpu::Extent3d {
|
||||||
|
width: size.x,
|
||||||
|
height: size.y,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let source_tex = self.source.frame.as_ref().unwrap().texture();
|
||||||
|
let dest_tex = self.dest.frame.as_ref().unwrap().texture();
|
||||||
|
|
||||||
|
let source_ict = wgpu::ImageCopyTexture {
|
||||||
|
texture: source_tex,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d::ZERO,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
};
|
||||||
|
|
||||||
|
let dest_ict = wgpu::ImageCopyTexture {
|
||||||
|
texture: dest_tex,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d::ZERO,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
};
|
||||||
|
|
||||||
|
encoder.copy_texture_to_texture(source_ict, dest_ict, size);
|
||||||
|
std::mem::swap(&mut self.source, &mut self.dest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ViewTarget {
|
||||||
|
device: Arc<wgpu::Device>,
|
||||||
|
/// The primary RenderTarget, likely a Surface
|
||||||
|
pub primary: FrameTarget,
|
||||||
|
pub chain: Option<TargetViewChain>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ViewTarget {
|
||||||
|
pub fn new(device: Arc<wgpu::Device>, primary: RenderTarget) -> Self {
|
||||||
|
Self {
|
||||||
|
device,
|
||||||
|
primary: FrameTarget::new(primary),
|
||||||
|
chain: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn size(&self) -> math::UVec2 {
|
||||||
|
self.primary.size()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn format(&self) -> wgpu::TextureFormat {
|
||||||
|
self.primary.format()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resize(&mut self, device: &wgpu::Device, size: math::UVec2) {
|
||||||
|
self.primary.render_target.resize(device, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cycle the target view chain, storing it in self, and returning a mutable borrow to it.
|
||||||
|
pub fn next_chain(&mut self, encoder: &mut wgpu::CommandEncoder) -> &mut TargetViewChain {
|
||||||
|
// TODO: check if chain has already been made. If it has, use next on it.
|
||||||
|
let _ = encoder;
|
||||||
|
let format = self.primary.format();
|
||||||
|
let size = self.primary.size();
|
||||||
|
|
||||||
|
let mut source = FrameTarget::new(RenderTarget::new_texture(&self.device, format, size));
|
||||||
|
source.create_frame();
|
||||||
|
source.create_frame_view();
|
||||||
|
|
||||||
|
let mut dest = FrameTarget::new(RenderTarget::new_texture(&self.device, format, size));
|
||||||
|
dest.create_frame();
|
||||||
|
dest.create_frame_view();
|
||||||
|
|
||||||
|
self.chain = Some(TargetViewChain {
|
||||||
|
source,
|
||||||
|
dest,
|
||||||
|
});
|
||||||
|
//self.reset_chain(encoder);
|
||||||
|
self.chain.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the [`wgpu::TextureView`] to render to
|
||||||
|
pub fn render_view(&self) -> &wgpu::TextureView {
|
||||||
|
let chain = self.chain.as_ref().unwrap();
|
||||||
|
chain.source.frame_view.as_ref().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Copy the chain target to the primary target
|
||||||
|
///
|
||||||
|
/// The primary target must have `wgpu::TextureUsages::COPY_DST`.
|
||||||
|
pub fn copy_to_primary(&self, encoder: &mut wgpu::CommandEncoder) {
|
||||||
|
let chain = self.chain.as_ref().unwrap();
|
||||||
|
let chain_tex = chain.source.frame.as_ref().unwrap().texture();
|
||||||
|
|
||||||
|
let source_ict = wgpu::ImageCopyTexture {
|
||||||
|
texture: chain_tex,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d::ZERO,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
};
|
||||||
|
|
||||||
|
let dest_tex = self.primary.frame.as_ref().unwrap().texture();
|
||||||
|
let dest_ict = wgpu::ImageCopyTexture {
|
||||||
|
texture: dest_tex,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d::ZERO,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
};
|
||||||
|
|
||||||
|
let size = self.primary.size();
|
||||||
|
let size = wgpu::Extent3d {
|
||||||
|
width: size.x,
|
||||||
|
height: size.y,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
encoder.copy_texture_to_texture(source_ict, dest_ict, size);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::World;
|
||||||
|
@ -7,7 +9,7 @@ use lyra_game_derive::RenderGraphLabel;
|
||||||
use tracing::{debug, instrument, warn};
|
use tracing::{debug, instrument, warn};
|
||||||
use winit::window::Window;
|
use winit::window::Window;
|
||||||
|
|
||||||
use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel, RenderGraphLabelValue, RenderTarget, SubGraphNode, TintPass, TintPassLabel, TintPassSlots};
|
use crate::render::graph::{BasePass, BasePassLabel, BasePassSlots, LightBasePass, LightBasePassLabel, LightCullComputePass, LightCullComputePassLabel, MeshPass, MeshesPassLabel, PresentPass, PresentPassLabel, RenderGraphLabelValue, RenderTarget, SubGraphNode, ViewTarget};
|
||||||
|
|
||||||
use super::graph::RenderGraph;
|
use super::graph::RenderGraph;
|
||||||
use super::{resource::RenderPipeline, render_job::RenderJob};
|
use super::{resource::RenderPipeline, render_job::RenderJob};
|
||||||
|
@ -114,7 +116,7 @@ impl BasicRenderer {
|
||||||
.find(|f| f.describe().srgb)
|
.find(|f| f.describe().srgb)
|
||||||
.unwrap_or(surface_caps.formats[0]);
|
.unwrap_or(surface_caps.formats[0]);
|
||||||
let config = wgpu::SurfaceConfiguration {
|
let config = wgpu::SurfaceConfiguration {
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
|
||||||
format: surface_format,
|
format: surface_format,
|
||||||
width: size.width,
|
width: size.width,
|
||||||
height: size.height,
|
height: size.height,
|
||||||
|
@ -127,35 +129,16 @@ impl BasicRenderer {
|
||||||
let device = Arc::new(device);
|
let device = Arc::new(device);
|
||||||
let queue = Arc::new(queue);
|
let queue = Arc::new(queue);
|
||||||
|
|
||||||
let surface_size = wgpu::Extent3d {
|
|
||||||
width: config.width,
|
|
||||||
height: config.height,
|
|
||||||
depth_or_array_layers: 1
|
|
||||||
};
|
|
||||||
let surface_target = RenderTarget::from_surface(surface, config);
|
let surface_target = RenderTarget::from_surface(surface, config);
|
||||||
|
let view_target = Rc::new(RefCell::new(ViewTarget::new(device.clone(), surface_target)));
|
||||||
|
|
||||||
let headless_texture = device.create_texture(&wgpu::TextureDescriptor {
|
let mut main_graph = RenderGraph::new(device.clone(), queue.clone(), view_target.clone());
|
||||||
label: Some("headless_texture"),
|
|
||||||
size: surface_size,
|
|
||||||
mip_level_count: 1,
|
|
||||||
sample_count: 1,
|
|
||||||
dimension: wgpu::TextureDimension::D2,
|
|
||||||
format: surface_format,
|
|
||||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT // we'll be rendering to it
|
|
||||||
| wgpu::TextureUsages::TEXTURE_BINDING,
|
|
||||||
view_formats: &[],
|
|
||||||
});
|
|
||||||
|
|
||||||
let headless_target = RenderTarget::from(headless_texture);
|
|
||||||
|
|
||||||
|
|
||||||
let mut main_graph = RenderGraph::new(device.clone(), queue.clone());
|
|
||||||
|
|
||||||
debug!("Adding base pass");
|
debug!("Adding base pass");
|
||||||
main_graph.add_node(BasePassLabel, BasePass::new(surface_target));
|
main_graph.add_node(BasePassLabel, BasePass::new());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut forward_plus_graph = RenderGraph::new(device.clone(), queue.clone());
|
let mut forward_plus_graph = RenderGraph::new(device.clone(), queue.clone(), view_target.clone());
|
||||||
|
|
||||||
debug!("Adding light base pass");
|
debug!("Adding light base pass");
|
||||||
forward_plus_graph.add_node(LightBasePassLabel, LightBasePass::new());
|
forward_plus_graph.add_node(LightBasePassLabel, LightBasePass::new());
|
||||||
|
@ -171,8 +154,8 @@ impl BasicRenderer {
|
||||||
main_graph.add_sub_graph(TestSubGraphLabel, forward_plus_graph);
|
main_graph.add_sub_graph(TestSubGraphLabel, forward_plus_graph);
|
||||||
main_graph.add_node(TestSubGraphLabel, SubGraphNode::new(TestSubGraphLabel,
|
main_graph.add_node(TestSubGraphLabel, SubGraphNode::new(TestSubGraphLabel,
|
||||||
vec![
|
vec![
|
||||||
RenderGraphLabelValue::from(BasePassSlots::WindowTextureView),
|
/* RenderGraphLabelValue::from(BasePassSlots::WindowTextureView),
|
||||||
RenderGraphLabelValue::from(BasePassSlots::MainRenderTarget),
|
RenderGraphLabelValue::from(BasePassSlots::MainRenderTarget), */
|
||||||
RenderGraphLabelValue::from(BasePassSlots::DepthTexture),
|
RenderGraphLabelValue::from(BasePassSlots::DepthTexture),
|
||||||
RenderGraphLabelValue::from(BasePassSlots::DepthTextureView),
|
RenderGraphLabelValue::from(BasePassSlots::DepthTextureView),
|
||||||
RenderGraphLabelValue::from(BasePassSlots::Camera),
|
RenderGraphLabelValue::from(BasePassSlots::Camera),
|
||||||
|
@ -181,12 +164,12 @@ impl BasicRenderer {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);//TintPassSlots::Frame);
|
//let present_pass_label = PresentPassLabel::new(BasePassSlots::Frame);//TintPassSlots::Frame);
|
||||||
let p = PresentPass::from_node_label(present_pass_label.clone());
|
let p = PresentPass::default();
|
||||||
main_graph.add_node(p.label.clone(), p);
|
main_graph.add_node(PresentPassLabel, p);
|
||||||
|
|
||||||
main_graph.add_edge(BasePassLabel, TestSubGraphLabel);
|
main_graph.add_edge(BasePassLabel, TestSubGraphLabel);
|
||||||
main_graph.add_edge(TestSubGraphLabel, present_pass_label);
|
main_graph.add_edge(TestSubGraphLabel, PresentPassLabel);
|
||||||
|
|
||||||
/* debug!("Adding base pass");
|
/* debug!("Adding base pass");
|
||||||
g.add_node(BasePassLabel, BasePass::new(surface_target));
|
g.add_node(BasePassLabel, BasePass::new(surface_target));
|
||||||
|
@ -259,9 +242,10 @@ impl Renderer for BasicRenderer {
|
||||||
self.size = new_size;
|
self.size = new_size;
|
||||||
|
|
||||||
// update surface config and the surface
|
// update surface config and the surface
|
||||||
let mut rt = self.graph.slot_value_mut(BasePassSlots::MainRenderTarget)
|
/* let mut rt = self.graph.slot_value_mut(BasePassSlots::MainRenderTarget)
|
||||||
.unwrap().as_render_target_mut().unwrap();
|
.unwrap().as_render_target_mut().unwrap();
|
||||||
rt.resize(&self.device, math::UVec2::new(new_size.width, new_size.height));
|
rt.resize(&self.device, math::UVec2::new(new_size.width, new_size.height)); */
|
||||||
|
self.graph.view_target_mut().resize(&self.device, math::UVec2::new(new_size.width, new_size.height));
|
||||||
/* rt.surface_config.width = new_size.width;
|
/* rt.surface_config.width = new_size.width;
|
||||||
rt.surface_config.height = new_size.height;
|
rt.surface_config.height = new_size.height;
|
||||||
rt.surface.configure(&self.device, &rt.surface_config); */
|
rt.surface.configure(&self.device, &rt.surface_config); */
|
||||||
|
@ -269,6 +253,8 @@ impl Renderer for BasicRenderer {
|
||||||
// update screen size resource in ecs
|
// update screen size resource in ecs
|
||||||
let mut world_ss = world.get_resource_mut::<ScreenSize>();
|
let mut world_ss = world.get_resource_mut::<ScreenSize>();
|
||||||
world_ss.0 = glam::UVec2::new(new_size.width, new_size.height);
|
world_ss.0 = glam::UVec2::new(new_size.width, new_size.height);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue