egui renderpass
This commit is contained in:
parent
393cfbbb63
commit
5814118d3f
710
crates/renderer/src/egui.rs
Normal file
710
crates/renderer/src/egui.rs
Normal file
|
@ -0,0 +1,710 @@
|
||||||
|
use std::{collections::BTreeMap, sync::Arc};
|
||||||
|
|
||||||
|
use ash::{prelude::VkResult, vk};
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
buffers::{Buffer, BufferDesc},
|
||||||
|
device::{self, DeviceOwned},
|
||||||
|
images::{Image, ImageDesc, ImageViewDesc},
|
||||||
|
render_graph::{
|
||||||
|
buffer_barrier, image_barrier, Access, Barrier, GraphResourceDesc, GraphResourceId,
|
||||||
|
PassDesc, RecordFn, RenderContext, RenderGraph,
|
||||||
|
},
|
||||||
|
texture,
|
||||||
|
util::Rect2D,
|
||||||
|
EguiState,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn egui_pre_pass(
|
||||||
|
dev: &device::Device,
|
||||||
|
rg: &mut RenderGraph,
|
||||||
|
textures: &mut crate::texture::TextureManager,
|
||||||
|
egui_state: &mut EguiState,
|
||||||
|
output: &egui::FullOutput,
|
||||||
|
) -> VkResult<()> {
|
||||||
|
// allocate resource ids for textures in tessellated list (imported from texture manager)
|
||||||
|
// define accesses for resource ids
|
||||||
|
|
||||||
|
// create textures for new egui textures
|
||||||
|
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));
|
||||||
|
if let Some(old) = egui_state.textures.insert(
|
||||||
|
*egui_id,
|
||||||
|
crate::EguiTextureInfo {
|
||||||
|
id: tid,
|
||||||
|
options: delta.options,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
textures.remove_texture(old.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate size for staging buffer.
|
||||||
|
// calculate size for staging image.
|
||||||
|
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 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::<egui::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()
|
||||||
|
.get_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();
|
||||||
|
let pos = delta.pos.unwrap();
|
||||||
|
let rect = Rect2D::new_from_size(
|
||||||
|
glam::ivec2(pos[0] as i32, pos[1] as i32),
|
||||||
|
glam::ivec2(delta.image.width() as i32, delta.image.height() as i32),
|
||||||
|
);
|
||||||
|
Some((*id, (old_offset, bytes, rect, alias)))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
// let tessellated = egui.tessellate(output.shapes, output.pixels_per_point);
|
||||||
|
|
||||||
|
aliased_images
|
||||||
|
};
|
||||||
|
|
||||||
|
let textures = output
|
||||||
|
.textures_delta
|
||||||
|
.set
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(egui_id, _)| {
|
||||||
|
egui_state
|
||||||
|
.lookup_texture(*egui_id)
|
||||||
|
.and_then(|tid| textures.get_texture(tid))
|
||||||
|
.map(|img| (*egui_id, img))
|
||||||
|
})
|
||||||
|
.map(|(id, img)| {
|
||||||
|
(
|
||||||
|
id,
|
||||||
|
rg.import_image(
|
||||||
|
img,
|
||||||
|
Access {
|
||||||
|
layout: Some(vk::ImageLayout::GENERAL),
|
||||||
|
..Access::undefined()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
|
let staging_buffer = rg.import_buffer(Arc::new(staging_buffer), Access::undefined());
|
||||||
|
let staging_image = rg.import_image(staging_image, Access::undefined());
|
||||||
|
|
||||||
|
let record = Box::new({
|
||||||
|
let textures = textures.clone();
|
||||||
|
move |ctx: &RenderContext| -> crate::Result<()> {
|
||||||
|
let staging_image = ctx.get_image(staging_image).unwrap().clone();
|
||||||
|
let staging_buffer = ctx.get_buffer(staging_buffer).unwrap();
|
||||||
|
|
||||||
|
for (id, (offset, _, rect, _)) in aliased_images {
|
||||||
|
let alias = unsafe {
|
||||||
|
staging_image.get_alias(ImageDesc {
|
||||||
|
name: Some(format!("egui-prepass-staging-aliased-{id:?}v").into()),
|
||||||
|
format: vk::Format::R8G8B8A8_UNORM,
|
||||||
|
extent: vk::Extent3D {
|
||||||
|
width: rect.width() as u32,
|
||||||
|
height: rect.height() as u32,
|
||||||
|
depth: 1,
|
||||||
|
},
|
||||||
|
usage: vk::ImageUsageFlags::TRANSFER_SRC
|
||||||
|
| vk::ImageUsageFlags::TRANSFER_DST,
|
||||||
|
queue_families: device::QueueFlags::empty(),
|
||||||
|
..Default::default()
|
||||||
|
})?
|
||||||
|
};
|
||||||
|
|
||||||
|
let texture = textures.get(&id).and_then(|id| ctx.get_image(*id)).unwrap();
|
||||||
|
|
||||||
|
let image: Barrier = image_barrier(
|
||||||
|
alias.handle(),
|
||||||
|
alias.format(),
|
||||||
|
Access {
|
||||||
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
layout: Some(vk::ImageLayout::UNDEFINED),
|
||||||
|
},
|
||||||
|
Access {
|
||||||
|
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(
|
||||||
|
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(),
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
|
||||||
|
let from_barrier = image_barrier(
|
||||||
|
alias.handle(),
|
||||||
|
alias.format(),
|
||||||
|
Access {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
|
},
|
||||||
|
Access {
|
||||||
|
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(),
|
||||||
|
Access {
|
||||||
|
stage: vk::PipelineStageFlags2::NONE,
|
||||||
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
layout: Some(vk::ImageLayout::GENERAL),
|
||||||
|
},
|
||||||
|
Access {
|
||||||
|
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: rect.top_left().x,
|
||||||
|
y: rect.top_left().y,
|
||||||
|
z: 0,
|
||||||
|
},
|
||||||
|
extent: alias.size(),
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
|
||||||
|
let image: Barrier = image_barrier(
|
||||||
|
texture.handle(),
|
||||||
|
texture.format(),
|
||||||
|
Access {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_WRITE,
|
||||||
|
layout: Some(vk::ImageLayout::TRANSFER_DST_OPTIMAL),
|
||||||
|
},
|
||||||
|
Access {
|
||||||
|
stage: vk::PipelineStageFlags2::ALL_COMMANDS,
|
||||||
|
mask: vk::AccessFlags2::empty(),
|
||||||
|
layout: Some(vk::ImageLayout::GENERAL),
|
||||||
|
},
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ctx.device
|
||||||
|
.dev()
|
||||||
|
.cmd_pipeline_barrier2(ctx.cmd.buffer(), &((&image).into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rg.add_pass(PassDesc {
|
||||||
|
reads: [
|
||||||
|
(
|
||||||
|
staging_buffer,
|
||||||
|
Access {
|
||||||
|
stage: vk::PipelineStageFlags2::TRANSFER,
|
||||||
|
mask: vk::AccessFlags2::TRANSFER_READ,
|
||||||
|
..Access::undefined()
|
||||||
|
},
|
||||||
|
),
|
||||||
|
(staging_image, Access::undefined()),
|
||||||
|
]
|
||||||
|
.to_vec(),
|
||||||
|
writes: textures
|
||||||
|
.iter()
|
||||||
|
.map(|(_, id)| {
|
||||||
|
(
|
||||||
|
*id,
|
||||||
|
Access {
|
||||||
|
layout: Some(vk::ImageLayout::GENERAL),
|
||||||
|
..Access::undefined()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
record,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// fn egui_pass()
|
||||||
|
pub fn egui_pass(
|
||||||
|
dev: &device::Device,
|
||||||
|
rg: &mut RenderGraph,
|
||||||
|
texture_handler: &mut crate::texture::TextureManager,
|
||||||
|
samplers: &mut crate::SamplerCache,
|
||||||
|
egui_state: &mut EguiState,
|
||||||
|
egui: &egui::Context,
|
||||||
|
output: egui::FullOutput,
|
||||||
|
target: GraphResourceId,
|
||||||
|
) -> VkResult<Vec<texture::TextureId>> {
|
||||||
|
let draw_data = egui.tessellate(output.shapes, output.pixels_per_point);
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
|
struct Vertex {
|
||||||
|
pos: glam::Vec2,
|
||||||
|
uv: glam::Vec2,
|
||||||
|
color: egui::epaint::Color32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct DrawCall(vk::DrawIndexedIndirectCommand);
|
||||||
|
unsafe impl bytemuck::Zeroable for DrawCall {}
|
||||||
|
unsafe impl bytemuck::Pod for DrawCall {}
|
||||||
|
|
||||||
|
let mut vertices = Vec::new();
|
||||||
|
let mut indices = Vec::new();
|
||||||
|
let mut draw_calls = Vec::new();
|
||||||
|
let mut textures = IndexMap::new();
|
||||||
|
let mut textures_indices = Vec::new();
|
||||||
|
for draw in draw_data {
|
||||||
|
let egui::epaint::Primitive::Mesh(mesh) = draw.primitive else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
draw_calls.push(DrawCall(vk::DrawIndexedIndirectCommand {
|
||||||
|
index_count: mesh.indices.len() as u32,
|
||||||
|
instance_count: 1,
|
||||||
|
first_index: indices.len() as u32,
|
||||||
|
vertex_offset: vertices.len() as i32,
|
||||||
|
first_instance: 0,
|
||||||
|
}));
|
||||||
|
|
||||||
|
vertices.extend(mesh.vertices.iter().map(|v| Vertex {
|
||||||
|
pos: glam::vec2(v.pos.x, v.pos.y),
|
||||||
|
uv: glam::vec2(v.uv.x, v.uv.y),
|
||||||
|
color: v.color,
|
||||||
|
}));
|
||||||
|
|
||||||
|
indices.extend(mesh.indices);
|
||||||
|
let texture = egui_state.textures.get(&mesh.texture_id).cloned().unwrap();
|
||||||
|
if !textures.contains_key(&texture.id) {
|
||||||
|
textures.insert(texture.id, texture);
|
||||||
|
}
|
||||||
|
let idx = textures.get_index_of(&texture.id).unwrap();
|
||||||
|
textures_indices.push(idx as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
let num_draw_calls = draw_calls.len();
|
||||||
|
let vertices_size = vertices.len() * size_of::<Vertex>();
|
||||||
|
let indices_size = indices.len() * size_of::<u32>();
|
||||||
|
let draw_calls_size = draw_calls.len() * size_of::<vk::DrawIndexedIndirectCommand>();
|
||||||
|
|
||||||
|
let (draw_staging, vertices, indices, draw_calls, texture_ids) = {
|
||||||
|
let staging_size = vertices_size + indices_size + draw_calls_size;
|
||||||
|
|
||||||
|
let mut staging = Buffer::new(
|
||||||
|
dev.clone(),
|
||||||
|
BufferDesc {
|
||||||
|
name: Some("egui-draw-staging".into()),
|
||||||
|
size: staging_size as u64,
|
||||||
|
usage: vk::BufferUsageFlags::TRANSFER_SRC,
|
||||||
|
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 mut map = staging.map()?;
|
||||||
|
|
||||||
|
let (st_vertices, rest) = map.split_at_mut(vertices_size);
|
||||||
|
let (st_indices, st_drawcalls) = rest.split_at_mut(indices_size);
|
||||||
|
st_vertices.copy_from_slice(bytemuck::cast_slice(&vertices));
|
||||||
|
st_indices.copy_from_slice(bytemuck::cast_slice(&indices));
|
||||||
|
st_drawcalls.copy_from_slice(bytemuck::cast_slice(&draw_calls));
|
||||||
|
}
|
||||||
|
let staging = rg.import_buffer(Arc::new(staging), Access::undefined());
|
||||||
|
|
||||||
|
let vertices = rg.add_resource(GraphResourceDesc::Buffer(BufferDesc {
|
||||||
|
name: Some("egui-draw-vertices".into()),
|
||||||
|
size: vertices_size as u64,
|
||||||
|
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
|
||||||
|
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
let indices = rg.add_resource(GraphResourceDesc::Buffer(BufferDesc {
|
||||||
|
name: Some("egui-draw-indices".into()),
|
||||||
|
size: indices_size as u64,
|
||||||
|
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDEX_BUFFER,
|
||||||
|
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
let draw_calls = rg.add_resource(GraphResourceDesc::Buffer(BufferDesc {
|
||||||
|
name: Some("egui-draw-draw_calls".into()),
|
||||||
|
size: draw_calls_size as u64,
|
||||||
|
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::INDIRECT_BUFFER,
|
||||||
|
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||||
|
..Default::default()
|
||||||
|
}));
|
||||||
|
|
||||||
|
let mut texture_ids = Buffer::new(
|
||||||
|
dev.clone(),
|
||||||
|
BufferDesc {
|
||||||
|
name: Some("egui-draw-texture_ids".into()),
|
||||||
|
size: (textures_indices.len() * size_of::<u32>()) as u64,
|
||||||
|
usage: vk::BufferUsageFlags::STORAGE_BUFFER,
|
||||||
|
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||||
|
alloc_flags: vk_mem::AllocationCreateFlags::HOST_ACCESS_SEQUENTIAL_WRITE,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
{
|
||||||
|
let mut map = texture_ids.map()?;
|
||||||
|
map.copy_from_slice(bytemuck::cast_slice(&textures_indices));
|
||||||
|
}
|
||||||
|
|
||||||
|
(staging, vertices, indices, draw_calls, texture_ids)
|
||||||
|
};
|
||||||
|
|
||||||
|
let descriptor_infos = textures
|
||||||
|
.values()
|
||||||
|
.map(|entry| {
|
||||||
|
let texture = texture_handler.get_texture(entry.id).unwrap();
|
||||||
|
let info = vk::DescriptorImageInfo {
|
||||||
|
sampler: samplers.get_sampler(entry.into_sampler_desc()).unwrap(),
|
||||||
|
image_view: texture
|
||||||
|
.get_view(ImageViewDesc {
|
||||||
|
kind: vk::ImageViewType::TYPE_2D,
|
||||||
|
format: texture.format(),
|
||||||
|
aspect: vk::ImageAspectFlags::COLOR,
|
||||||
|
mip_range: (0..1).into(),
|
||||||
|
layer_range: (0..1).into(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.unwrap(),
|
||||||
|
image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
info
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let uniform_info = vk::DescriptorBufferInfo {
|
||||||
|
buffer: texture_ids.buffer(),
|
||||||
|
offset: 0,
|
||||||
|
range: texture_ids.len(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let descriptor_writes = descriptor_infos
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, info)| {
|
||||||
|
vk::WriteDescriptorSet::default()
|
||||||
|
.image_info(core::slice::from_ref(info))
|
||||||
|
.descriptor_count(1)
|
||||||
|
.descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER)
|
||||||
|
.dst_set(egui_state.descriptor_set)
|
||||||
|
.dst_binding(EguiState::TEXTURE_BINDING)
|
||||||
|
.dst_array_element(i as u32)
|
||||||
|
})
|
||||||
|
.chain(core::iter::once({
|
||||||
|
vk::WriteDescriptorSet::default()
|
||||||
|
.buffer_info(core::slice::from_ref(&uniform_info))
|
||||||
|
.descriptor_count(1)
|
||||||
|
.dst_binding(EguiState::UNIFORM_BINDING)
|
||||||
|
.descriptor_type(vk::DescriptorType::STORAGE_BUFFER)
|
||||||
|
.dst_array_element(0)
|
||||||
|
.dst_set(egui_state.descriptor_set)
|
||||||
|
}))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
dev.dev().update_descriptor_sets(&descriptor_writes, &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let to_remove_tex_ids = output
|
||||||
|
.textures_delta
|
||||||
|
.free
|
||||||
|
.iter()
|
||||||
|
.filter_map(|id| egui_state.textures.get(id).cloned())
|
||||||
|
.map(|entry| entry.id)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let reads = textures
|
||||||
|
.keys()
|
||||||
|
.filter_map(|id| {
|
||||||
|
texture_handler
|
||||||
|
.get_texture(*id)
|
||||||
|
.map(|img| (rg.import_image(img, Access::general()), Access::general()))
|
||||||
|
})
|
||||||
|
.chain([(target, Access::color_attachment_read_write())])
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let writes = [(target, Access::color_attachment_write_only())].to_vec();
|
||||||
|
|
||||||
|
let record: Box<RecordFn> = Box::new({
|
||||||
|
let pipeline = egui_state.pipeline.clone();
|
||||||
|
let pipeline_layout = egui_state.pipeline_layout.clone();
|
||||||
|
let descriptor_set = egui_state.descriptor_set;
|
||||||
|
|
||||||
|
move |ctx: &RenderContext| -> crate::Result<()> {
|
||||||
|
let cmd = &ctx.cmd;
|
||||||
|
let staging = ctx.get_buffer(draw_staging).unwrap();
|
||||||
|
let vertices = ctx.get_buffer(vertices).unwrap();
|
||||||
|
let indices = ctx.get_buffer(indices).unwrap();
|
||||||
|
let draw_calls = ctx.get_buffer(draw_calls).unwrap();
|
||||||
|
let target = ctx.get_image(target).unwrap();
|
||||||
|
|
||||||
|
cmd.copy_buffers(
|
||||||
|
staging.buffer(),
|
||||||
|
vertices.buffer(),
|
||||||
|
&[vk::BufferCopy {
|
||||||
|
src_offset: 0,
|
||||||
|
dst_offset: 0,
|
||||||
|
size: vertices_size as u64,
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
cmd.copy_buffers(
|
||||||
|
staging.buffer(),
|
||||||
|
indices.buffer(),
|
||||||
|
&[vk::BufferCopy {
|
||||||
|
src_offset: vertices_size as u64,
|
||||||
|
dst_offset: 0,
|
||||||
|
size: indices_size as u64,
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
cmd.copy_buffers(
|
||||||
|
staging.buffer(),
|
||||||
|
draw_calls.buffer(),
|
||||||
|
&[vk::BufferCopy {
|
||||||
|
src_offset: (vertices_size + indices_size) as u64,
|
||||||
|
dst_offset: 0,
|
||||||
|
size: draw_calls_size as u64,
|
||||||
|
}],
|
||||||
|
);
|
||||||
|
|
||||||
|
let barriers = [
|
||||||
|
buffer_barrier(
|
||||||
|
vertices.handle(),
|
||||||
|
0,
|
||||||
|
vertices.len(),
|
||||||
|
Access::transfer_write(),
|
||||||
|
Access::vertex_read(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
buffer_barrier(
|
||||||
|
indices.handle(),
|
||||||
|
0,
|
||||||
|
indices.len(),
|
||||||
|
Access::transfer_write(),
|
||||||
|
Access::index_read(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
buffer_barrier(
|
||||||
|
draw_calls.handle(),
|
||||||
|
0,
|
||||||
|
draw_calls.len(),
|
||||||
|
Access::transfer_write(),
|
||||||
|
Access::indirect_read(),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
unsafe {
|
||||||
|
ctx.device.dev().cmd_pipeline_barrier2(
|
||||||
|
cmd.buffer(),
|
||||||
|
&vk::DependencyInfo::default().buffer_memory_barriers(&barriers),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.bind_pipeline(&pipeline);
|
||||||
|
cmd.bind_indices(indices.buffer(), 0, vk::IndexType::UINT32);
|
||||||
|
cmd.bind_vertices(vertices.buffer(), 0);
|
||||||
|
cmd.push_constants(
|
||||||
|
&pipeline_layout,
|
||||||
|
vk::ShaderStageFlags::VERTEX,
|
||||||
|
0,
|
||||||
|
bytemuck::cast_slice(
|
||||||
|
&[target.width() as f32, target.height() as f32].map(|f| f.to_bits()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
cmd.bind_descriptor_sets(
|
||||||
|
&pipeline_layout,
|
||||||
|
vk::PipelineBindPoint::GRAPHICS,
|
||||||
|
&[descriptor_set],
|
||||||
|
);
|
||||||
|
cmd.draw_indexed_indirect(
|
||||||
|
draw_calls.buffer(),
|
||||||
|
0,
|
||||||
|
num_draw_calls as u32,
|
||||||
|
size_of::<vk::DrawIndexedIndirectCommand>() as u32,
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
rg.add_pass(PassDesc {
|
||||||
|
reads,
|
||||||
|
writes,
|
||||||
|
record,
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(to_remove_tex_ids)
|
||||||
|
}
|
|
@ -38,6 +38,8 @@ use raw_window_handle::RawDisplayHandle;
|
||||||
mod buffers;
|
mod buffers;
|
||||||
mod commands;
|
mod commands;
|
||||||
mod device;
|
mod device;
|
||||||
|
#[path = "egui.rs"]
|
||||||
|
mod egui_pass;
|
||||||
mod images;
|
mod images;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
mod render_graph;
|
mod render_graph;
|
||||||
|
|
Loading…
Reference in a new issue