rendergraph work that is probably all for nothing
This commit is contained in:
parent
e8d4e1af98
commit
d66071f7bb
|
@ -5,17 +5,20 @@ use std::{collections::BTreeMap, fmt::Debug, sync::Arc};
|
||||||
use crate::{
|
use crate::{
|
||||||
buffers::{Buffer, BufferDesc},
|
buffers::{Buffer, BufferDesc},
|
||||||
commands, def_monotonic_id,
|
commands, def_monotonic_id,
|
||||||
device::{self, Device, DeviceOwned},
|
device::{self, DeviceOwned},
|
||||||
images::{self, Image, ImageDesc},
|
images::{self, Image, ImageDesc, SUBRESOURCERANGE_COLOR_ALL},
|
||||||
|
texture,
|
||||||
util::{self, Rgba},
|
util::{self, Rgba},
|
||||||
SwapchainFrame,
|
EguiState, SwapchainFrame,
|
||||||
};
|
};
|
||||||
use ash::vk;
|
use ash::{prelude::VkResult, vk};
|
||||||
|
use egui::Color32;
|
||||||
|
use itertools::Itertools;
|
||||||
use petgraph::visit::NodeRef;
|
use petgraph::visit::NodeRef;
|
||||||
|
|
||||||
def_monotonic_id!(pub RenderGraphResourceId);
|
def_monotonic_id!(pub RenderGraphResourceId);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum RenderGraphResourceDesc {
|
pub enum RenderGraphResourceDesc {
|
||||||
Image(ImageDesc),
|
Image(ImageDesc),
|
||||||
Buffer(BufferDesc),
|
Buffer(BufferDesc),
|
||||||
|
@ -50,9 +53,10 @@ struct AttachmentInfo {
|
||||||
store: StoreOp,
|
store: StoreOp,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderContext {
|
pub struct RenderContext<'a> {
|
||||||
device: device::Device,
|
device: device::Device,
|
||||||
cmd: commands::SingleUseCommand,
|
cmd: commands::SingleUseCommand,
|
||||||
|
resources: &'a BTreeMap<RenderGraphResourceId, RenderGraphResource>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Default)]
|
#[derive(Debug, Clone, Copy, Default)]
|
||||||
|
@ -72,15 +76,450 @@ impl ResourceAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct EguiPrePass {
|
||||||
|
out_resources:
|
||||||
|
BTreeMap<egui::TextureId, (RenderGraphResourceId, texture::TextureId, ResourceAccess)>,
|
||||||
|
staging_image: Arc<Image>,
|
||||||
|
staging_buffer: Arc<Buffer>,
|
||||||
|
aliased_images: BTreeMap<egui::TextureId, (usize, usize, [usize; 2], Image)>,
|
||||||
|
tessellated: Vec<egui::ClippedPrimitive>,
|
||||||
|
texture_data: BTreeMap<egui::TextureId, egui::epaint::ImageDelta>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for EguiPrePass {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("EguiPrePass")
|
||||||
|
.field("out_resources", &self.out_resources)
|
||||||
|
.finish_non_exhaustive()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EguiPrePass {
|
||||||
|
pub fn new(
|
||||||
|
dev: &device::Device,
|
||||||
|
rg: &mut RenderGraph,
|
||||||
|
textures: &mut crate::texture::TextureManager,
|
||||||
|
egui_state: &mut EguiState,
|
||||||
|
egui: &egui::Context,
|
||||||
|
output: egui::FullOutput,
|
||||||
|
) -> VkResult<Self> {
|
||||||
|
// calculate size for staging buffer.
|
||||||
|
// calculate size for staging image.
|
||||||
|
// allocate resource ids for textures in tessellated list (imported from texture manager)
|
||||||
|
// define accesses for resource ids
|
||||||
|
for (egui_id, delta) in output
|
||||||
|
.textures_delta
|
||||||
|
.set
|
||||||
|
.iter()
|
||||||
|
.filter(|(_, image)| image.is_whole())
|
||||||
|
{
|
||||||
|
let image = Image::new(
|
||||||
|
dev.clone(),
|
||||||
|
ImageDesc {
|
||||||
|
name: Some(format!("egui-texture-{egui_id:?}").into()),
|
||||||
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
|
extent: vk::Extent3D {
|
||||||
|
width: delta.image.width() as u32,
|
||||||
|
height: delta.image.height() as u32,
|
||||||
|
depth: 1,
|
||||||
|
},
|
||||||
|
usage: vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST,
|
||||||
|
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let tid = textures.insert_image(Arc::new(image));
|
||||||
|
egui_state.textures.insert(
|
||||||
|
*egui_id,
|
||||||
|
crate::EguiTextureInfo {
|
||||||
|
id: tid,
|
||||||
|
options: delta.options,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (staging_size, image_size) = output.textures_delta.set.iter().fold(
|
||||||
|
(0usize, 0usize),
|
||||||
|
|(mut buffer, mut image), (_id, delta)| {
|
||||||
|
let bytes =
|
||||||
|
delta.image.height() * delta.image.width() * delta.image.bytes_per_pixel();
|
||||||
|
if !delta.is_whole() {
|
||||||
|
image = image.max(bytes);
|
||||||
|
}
|
||||||
|
buffer = buffer + bytes;
|
||||||
|
|
||||||
|
(buffer, image)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
let tessellated = egui.tessellate(output.shapes, output.pixels_per_point);
|
||||||
|
|
||||||
|
let mut staging_buffer = Buffer::new(
|
||||||
|
dev.clone(),
|
||||||
|
BufferDesc {
|
||||||
|
name: Some("egui-prepass-staging-buffer".into()),
|
||||||
|
size: staging_size as u64,
|
||||||
|
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
||||||
|
queue_families: device::QueueFlags::empty(),
|
||||||
|
mem_usage: vk_mem::MemoryUsage::AutoPreferHost,
|
||||||
|
alloc_flags: vk_mem::AllocationCreateFlags::MAPPED
|
||||||
|
| vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE
|
||||||
|
| vk_mem::AllocationCreateFlags::STRATEGY_FIRST_FIT,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
let staging_image = Arc::new(Image::new(
|
||||||
|
dev.clone(),
|
||||||
|
ImageDesc {
|
||||||
|
name: Some("egui-prepass-staging-buffer".into()),
|
||||||
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
|
extent: vk::Extent3D {
|
||||||
|
width: (image_size / 2) as u32,
|
||||||
|
height: (image_size - (image_size / 2)) as u32,
|
||||||
|
depth: 1,
|
||||||
|
},
|
||||||
|
usage: vk::ImageUsageFlags::TRANSFER_SRC | vk::ImageUsageFlags::TRANSFER_DST,
|
||||||
|
queue_families: device::QueueFlags::empty(),
|
||||||
|
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?);
|
||||||
|
|
||||||
|
let aliased_images = {
|
||||||
|
let mut staging_map = staging_buffer.map()?;
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
|
let aliased_images = output
|
||||||
|
.textures_delta
|
||||||
|
.set
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(id, delta)| {
|
||||||
|
let bytes =
|
||||||
|
delta.image.height() * delta.image.width() * delta.image.bytes_per_pixel();
|
||||||
|
|
||||||
|
let mem = &mut staging_map[offset..offset + bytes];
|
||||||
|
match &delta.image {
|
||||||
|
egui::ImageData::Color(arc) => {
|
||||||
|
let slice = unsafe {
|
||||||
|
core::slice::from_raw_parts(
|
||||||
|
arc.pixels.as_ptr().cast::<u8>(),
|
||||||
|
arc.pixels.len() * size_of::<Color32>(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
mem[..slice.len()].copy_from_slice(slice);
|
||||||
|
}
|
||||||
|
egui::ImageData::Font(font_image) => {
|
||||||
|
for (i, c) in font_image.srgba_pixels(None).enumerate() {
|
||||||
|
let bytes = c.to_array();
|
||||||
|
mem[i * 4..(i + 1) * 4].copy_from_slice(&bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let old_offset = offset;
|
||||||
|
offset += bytes;
|
||||||
|
|
||||||
|
if !delta.is_whole() {
|
||||||
|
unsafe {
|
||||||
|
let alias = staging_image
|
||||||
|
.clone()
|
||||||
|
.alias(ImageDesc {
|
||||||
|
name: Some(
|
||||||
|
format!("egui-prepass-staging-aliased-{id:?}").into(),
|
||||||
|
),
|
||||||
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
|
extent: vk::Extent3D {
|
||||||
|
width: delta.image.width() as u32,
|
||||||
|
height: delta.image.height() as u32,
|
||||||
|
depth: 1,
|
||||||
|
},
|
||||||
|
usage: vk::ImageUsageFlags::TRANSFER_SRC
|
||||||
|
| vk::ImageUsageFlags::TRANSFER_DST,
|
||||||
|
queue_families: device::QueueFlags::empty(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
Some((*id, (old_offset, bytes, delta.pos.unwrap(), alias)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
aliased_images
|
||||||
|
};
|
||||||
|
|
||||||
|
let out_resources = tessellated
|
||||||
|
.iter()
|
||||||
|
.filter_map(|prim| {
|
||||||
|
if let egui::epaint::Primitive::Mesh(ref mesh) = prim.primitive {
|
||||||
|
Some(mesh.texture_id)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.dedup()
|
||||||
|
.filter_map(|egui_id| {
|
||||||
|
egui_state
|
||||||
|
.lookup_texture(egui_id)
|
||||||
|
.and_then(|tid| textures.get_texture(tid).map(|image| (egui_id, tid, image)))
|
||||||
|
})
|
||||||
|
.map(|(egui_id, tid, image)| {
|
||||||
|
let rid = rg.import_image(
|
||||||
|
image,
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
layout: Some(vk::ImageLayout::GENERAL),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
(
|
||||||
|
egui_id,
|
||||||
|
(
|
||||||
|
rid,
|
||||||
|
tid,
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
aliased_images,
|
||||||
|
staging_buffer: Arc::new(staging_buffer),
|
||||||
|
staging_image,
|
||||||
|
out_resources,
|
||||||
|
tessellated,
|
||||||
|
texture_data: output
|
||||||
|
.textures_delta
|
||||||
|
.set
|
||||||
|
.into_iter()
|
||||||
|
.collect::<BTreeMap<_, _>>(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pass for EguiPrePass {
|
||||||
|
fn get_read_resource_access(&self, _id: RenderGraphResourceId) -> ResourceAccess {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_write_resource_access(&self, id: RenderGraphResourceId) -> ResourceAccess {
|
||||||
|
self.out_resources
|
||||||
|
.iter()
|
||||||
|
.find(|(_, (id2, _, _))| *id2 == id)
|
||||||
|
.map(|(_, (_, _, access))| *access)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_queue_capability_requirements(&self) -> device::QueueFlags {
|
||||||
|
device::QueueFlags::TRANSFER
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_read_dependencies<'a>(&'a self) -> Box<dyn Iterator<Item = RenderGraphResourceId> + 'a> {
|
||||||
|
Box::new([].into_iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_write_dependencies<'a>(
|
||||||
|
&'a self,
|
||||||
|
) -> Box<dyn Iterator<Item = RenderGraphResourceId> + 'a> {
|
||||||
|
Box::new(self.out_resources.values().map(|(id, _, _)| *id))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record(&self, ctx: &RenderContext) -> crate::Result<()> {
|
||||||
|
let buffer: Barrier = buffer_barrier(
|
||||||
|
self.staging_buffer.handle(),
|
||||||
|
0,
|
||||||
|
self.staging_buffer.len(),
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
layout: None,
|
||||||
|
},
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_READ,
|
||||||
|
layout: None,
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ctx.device
|
||||||
|
.dev()
|
||||||
|
.cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&buffer).into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id, (offset, _, pos, alias)) in &self.aliased_images {
|
||||||
|
let image: Barrier = image_barrier(
|
||||||
|
alias.handle(),
|
||||||
|
alias.format(),
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
layout: Some(vk::ImageLayout::UNDEFINED),
|
||||||
|
},
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ctx.device
|
||||||
|
.dev()
|
||||||
|
.cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&image).into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.cmd.copy_buffer_to_image(
|
||||||
|
self.staging_buffer.handle(),
|
||||||
|
alias.handle(),
|
||||||
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
&[vk::BufferImageCopy {
|
||||||
|
buffer_offset: *offset as u64,
|
||||||
|
buffer_row_length: alias.width(),
|
||||||
|
buffer_image_height: alias.height(),
|
||||||
|
image_subresource: vk::ImageSubresourceLayers::default()
|
||||||
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.mip_level(0)
|
||||||
|
.layer_count(1),
|
||||||
|
image_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
|
||||||
|
image_extent: alias.size(),
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
|
||||||
|
//self.
|
||||||
|
let Some(RenderGraphResource::ImportedImage(texture)) = self
|
||||||
|
.out_resources
|
||||||
|
.get(id)
|
||||||
|
.and_then(|(id, _, _)| ctx.resources.get(id))
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let from_barrier = image_barrier(
|
||||||
|
alias.handle(),
|
||||||
|
alias.format(),
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
|
},
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_READ,
|
||||||
|
layout: Some(vk::ImageLayout::TRANSFER_SRC_OPTIMAL),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let to_barrier = image_barrier(
|
||||||
|
texture.handle(),
|
||||||
|
texture.format(),
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
layout: Some(vk::ImageLayout::GENERAL),
|
||||||
|
},
|
||||||
|
ResourceAccess {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ctx.device.dev().cmd_pipeline_barrier2(
|
||||||
|
ctx.cmd.buffer(),
|
||||||
|
&vk::DependencyInfo::default()
|
||||||
|
.image_memory_barriers(&[from_barrier, to_barrier]),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ctx.cmd.copy_images(
|
||||||
|
alias.handle(),
|
||||||
|
vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
||||||
|
texture.handle(),
|
||||||
|
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||||
|
&[vk::ImageCopy {
|
||||||
|
src_subresource: vk::ImageSubresourceLayers::default()
|
||||||
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.mip_level(0)
|
||||||
|
.layer_count(1),
|
||||||
|
src_offset: vk::Offset3D { x: 0, y: 0, z: 0 },
|
||||||
|
dst_subresource: vk::ImageSubresourceLayers::default()
|
||||||
|
.aspect_mask(vk::ImageAspectFlags::COLOR)
|
||||||
|
.base_array_layer(0)
|
||||||
|
.mip_level(0)
|
||||||
|
.layer_count(1),
|
||||||
|
dst_offset: vk::Offset3D {
|
||||||
|
x: pos[0] as i32,
|
||||||
|
y: pos[1] as i32,
|
||||||
|
z: 0,
|
||||||
|
},
|
||||||
|
extent: alias.size(),
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct EguiRenderPass {
|
||||||
|
descriptor_set: vk::DescriptorSet,
|
||||||
|
vertices: Buffer,
|
||||||
|
indices: Buffer,
|
||||||
|
draw_calls: Buffer,
|
||||||
|
texture_ids: Buffer,
|
||||||
|
textures_to_free: Vec<crate::texture::TextureId>,
|
||||||
|
num_draw_calls: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pass for EguiRenderPass {
|
||||||
|
fn get_read_resource_access(&self, id: RenderGraphResourceId) -> ResourceAccess {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_write_resource_access(&self, id: RenderGraphResourceId) -> ResourceAccess {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_queue_capability_requirements(&self) -> device::QueueFlags {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_read_dependencies<'a>(&'a self) -> Box<dyn Iterator<Item = RenderGraphResourceId> + 'a> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_write_dependencies<'a>(
|
||||||
|
&'a self,
|
||||||
|
) -> Box<dyn Iterator<Item = RenderGraphResourceId> + 'a> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn record(&self, ctx: &RenderContext) -> crate::Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Pass: Debug + Send {
|
pub trait Pass: Debug + Send {
|
||||||
fn get_read_resource_access(&self, id: RenderGraphResourceId) -> ResourceAccess;
|
fn get_read_resource_access(&self, id: RenderGraphResourceId) -> ResourceAccess;
|
||||||
fn get_write_resource_access(&self, id: RenderGraphResourceId) -> ResourceAccess;
|
fn get_write_resource_access(&self, id: RenderGraphResourceId) -> ResourceAccess;
|
||||||
/// returns the layout the pass requires an image dependency to be in prior
|
|
||||||
/// to the pass.
|
|
||||||
fn get_layout_of_in_image_dependency(&self, id: RenderGraphResourceId) -> vk::ImageLayout;
|
|
||||||
/// returns the layout the pass will leave an image dependency in after the
|
|
||||||
/// pass.
|
|
||||||
fn get_layout_of_out_image_dependency(&self, id: RenderGraphResourceId) -> vk::ImageLayout;
|
|
||||||
/// mask of the queue capability requirements of this pass.
|
/// mask of the queue capability requirements of this pass.
|
||||||
fn get_queue_capability_requirements(&self) -> device::QueueFlags;
|
fn get_queue_capability_requirements(&self) -> device::QueueFlags;
|
||||||
/// returns an iterator over all (in) dependencies.
|
/// returns an iterator over all (in) dependencies.
|
||||||
|
@ -88,7 +527,7 @@ pub trait Pass: Debug + Send {
|
||||||
fn get_write_dependencies<'a>(&'a self)
|
fn get_write_dependencies<'a>(&'a self)
|
||||||
-> Box<dyn Iterator<Item = RenderGraphResourceId> + 'a>;
|
-> Box<dyn Iterator<Item = RenderGraphResourceId> + 'a>;
|
||||||
|
|
||||||
fn record(self: Box<Self>, ctx: &RenderContext) -> crate::Result<()>;
|
fn record(&self, ctx: &RenderContext) -> crate::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
def_monotonic_id!(pub RenderGraphPassId);
|
def_monotonic_id!(pub RenderGraphPassId);
|
||||||
|
@ -166,6 +605,24 @@ impl RenderGraph {
|
||||||
// https://github.com/EmbarkStudios/kajiya/blob/main/crates/lib/kajiya-rg/src/graph.rs
|
// https://github.com/EmbarkStudios/kajiya/blob/main/crates/lib/kajiya-rg/src/graph.rs
|
||||||
// https://themaister.net/blog/2017/08/15/render-graphs-and-vulkan-a-deep-dive/
|
// https://themaister.net/blog/2017/08/15/render-graphs-and-vulkan-a-deep-dive/
|
||||||
pub fn resolve(mut self, device: device::Device) -> crate::Result<()> {
|
pub fn resolve(mut self, device: device::Device) -> crate::Result<()> {
|
||||||
|
// create internal resources:
|
||||||
|
for (&id, desc) in self.resource_descs.iter() {
|
||||||
|
match desc.clone() {
|
||||||
|
RenderGraphResourceDesc::Image(image_desc) => {
|
||||||
|
self.resources.insert(
|
||||||
|
id,
|
||||||
|
RenderGraphResource::Image(Image::new(device.clone(), image_desc)?),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
RenderGraphResourceDesc::Buffer(buffer_desc) => {
|
||||||
|
self.resources.insert(
|
||||||
|
id,
|
||||||
|
RenderGraphResource::Buffer(Buffer::new(device.clone(), buffer_desc)?),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
eprintln!("{:#?}", &self);
|
eprintln!("{:#?}", &self);
|
||||||
let mut last_write = BTreeMap::new();
|
let mut last_write = BTreeMap::new();
|
||||||
|
|
||||||
|
@ -280,7 +737,8 @@ impl RenderGraph {
|
||||||
let pool =
|
let pool =
|
||||||
commands::SingleUseCommandPool::new(device.clone(), device.graphics_queue().clone())?;
|
commands::SingleUseCommandPool::new(device.clone(), device.graphics_queue().clone())?;
|
||||||
|
|
||||||
let tasks = topological_map
|
let resources = &self.resources;
|
||||||
|
let cmds = topological_map
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(set, accesses)| {
|
.map(|(set, accesses)| {
|
||||||
let pool = pool.clone();
|
let pool = pool.clone();
|
||||||
|
@ -294,39 +752,43 @@ impl RenderGraph {
|
||||||
|
|
||||||
// transitions
|
// transitions
|
||||||
for (&id, &access) in accesses.iter() {
|
for (&id, &access) in accesses.iter() {
|
||||||
self.transition_resource_to(device.dev(), unsafe { &cmd.buffer() }, id, access);
|
Self::transition_resource_to(
|
||||||
|
&mut self.accesses,
|
||||||
|
resources,
|
||||||
|
device.dev(),
|
||||||
|
unsafe { &cmd.buffer() },
|
||||||
|
id,
|
||||||
|
access,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let task = smol::spawn(async move {
|
let ctx = RenderContext {
|
||||||
let ctx = RenderContext { device, cmd };
|
device,
|
||||||
|
cmd,
|
||||||
|
resources,
|
||||||
|
};
|
||||||
|
|
||||||
for pass in passes {
|
for pass in &passes {
|
||||||
pass.record(&ctx)?;
|
pass.record(&ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::Result::Ok(ctx.cmd)
|
crate::Result::Ok(ctx.cmd)
|
||||||
});
|
|
||||||
|
|
||||||
crate::Result::Ok(task)
|
|
||||||
})
|
})
|
||||||
.collect::<crate::Result<Vec<_>>>()?;
|
.collect::<crate::Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let commands = smol::block_on(futures::future::join_all(tasks))
|
|
||||||
.into_iter()
|
|
||||||
.collect::<crate::Result<Vec<_>>>()?;
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transition_resource_to(
|
fn transition_resource_to(
|
||||||
&mut self,
|
accesses: &mut BTreeMap<RenderGraphResourceId, ResourceAccess>,
|
||||||
|
resources: &BTreeMap<RenderGraphResourceId, RenderGraphResource>,
|
||||||
dev: &ash::Device,
|
dev: &ash::Device,
|
||||||
cmd: &vk::CommandBuffer,
|
cmd: &vk::CommandBuffer,
|
||||||
id: RenderGraphResourceId,
|
id: RenderGraphResourceId,
|
||||||
access: ResourceAccess,
|
access: ResourceAccess,
|
||||||
) {
|
) {
|
||||||
let old_access = self.accesses.get(&id);
|
let old_access = accesses.get(&id);
|
||||||
let res = self.resources.get(&id);
|
let res = resources.get(&id);
|
||||||
|
|
||||||
if let (Some(&old_access), Some(res)) = (old_access, res) {
|
if let (Some(&old_access), Some(res)) = (old_access, res) {
|
||||||
let barrier: Barrier = match res {
|
let barrier: Barrier = match res {
|
||||||
|
@ -348,7 +810,7 @@ impl RenderGraph {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.accesses.insert(id, access);
|
accesses.insert(id, access);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
dev.cmd_pipeline_barrier2(*cmd, &((&barrier).into()));
|
dev.cmd_pipeline_barrier2(*cmd, &((&barrier).into()));
|
||||||
|
@ -459,19 +921,6 @@ mod tests {
|
||||||
fn get_write_resource_access(&self, _id: RenderGraphResourceId) -> ResourceAccess {
|
fn get_write_resource_access(&self, _id: RenderGraphResourceId) -> ResourceAccess {
|
||||||
ResourceAccess::default()
|
ResourceAccess::default()
|
||||||
}
|
}
|
||||||
fn get_layout_of_in_image_dependency(
|
|
||||||
&self,
|
|
||||||
_id: RenderGraphResourceId,
|
|
||||||
) -> vk::ImageLayout {
|
|
||||||
$layout_in
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_layout_of_out_image_dependency(
|
|
||||||
&self,
|
|
||||||
_id: RenderGraphResourceId,
|
|
||||||
) -> vk::ImageLayout {
|
|
||||||
$layout_out
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_queue_capability_requirements(&self) -> device::QueueFlags {
|
fn get_queue_capability_requirements(&self) -> device::QueueFlags {
|
||||||
$queue
|
$queue
|
||||||
|
@ -489,7 +938,7 @@ mod tests {
|
||||||
Box::new(self.1.iter().cloned())
|
Box::new(self.1.iter().cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record(self: Box<Self>, _ctx: &RenderContext) -> crate::Result<()> {
|
fn record(&self, _ctx: &RenderContext) -> crate::Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue