stuff: slight refactoring
This commit is contained in:
parent
9802bec8b0
commit
c70c1591db
|
@ -6,6 +6,8 @@ edition = "2021"
|
|||
[dependencies]
|
||||
winit = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
smol = { workspace = true }
|
||||
glam = { workspace = true }
|
||||
tracing-subscriber = { workspace = true }
|
||||
renderer = { path = "../renderer" }
|
||||
|
||||
|
|
|
@ -444,12 +444,12 @@ impl SingleUseCommand {
|
|||
);
|
||||
}
|
||||
}
|
||||
pub fn bind_vertices(&self, buffer: vk::Buffer, offset: u64) {
|
||||
pub fn bind_vertex_buffers(&self, buffers: &[vk::Buffer], offsets: &[u64]) {
|
||||
assert_eq!(self.state(), CommandBufferState::Recording);
|
||||
unsafe {
|
||||
self.device()
|
||||
.dev()
|
||||
.cmd_bind_vertex_buffers(self.buffer(), 0, &[buffer], &[offset]);
|
||||
.cmd_bind_vertex_buffers(self.buffer(), 0, buffers, offsets);
|
||||
}
|
||||
}
|
||||
pub fn bind_indices(&self, buffer: vk::Buffer, offset: u64, kind: vk::IndexType) {
|
||||
|
|
|
@ -245,6 +245,9 @@ impl Device {
|
|||
pub fn graphics_queue(&self) -> &Queue {
|
||||
&self.0.main_queue
|
||||
}
|
||||
pub fn transfer_queue(&self) -> &Queue {
|
||||
&self.0.transfer_queue
|
||||
}
|
||||
pub fn present_queue(&self) -> &Queue {
|
||||
&self.0.present_queue
|
||||
}
|
||||
|
|
|
@ -712,7 +712,7 @@ pub fn egui_pass(
|
|||
|
||||
cmd.bind_pipeline(&pipeline);
|
||||
cmd.bind_indices(indices.buffer(), 0, vk::IndexType::UINT32);
|
||||
cmd.bind_vertices(vertices.buffer(), 0);
|
||||
cmd.bind_vertex_buffers(&[vertices.buffer()], &[0]);
|
||||
cmd.push_constants(
|
||||
&pipeline_layout,
|
||||
vk::ShaderStageFlags::VERTEX,
|
||||
|
|
|
@ -43,9 +43,9 @@ mod egui_pass;
|
|||
mod images;
|
||||
mod pipeline;
|
||||
mod render_graph;
|
||||
mod rendering;
|
||||
pub mod rendering;
|
||||
mod sync;
|
||||
mod util;
|
||||
pub mod util;
|
||||
|
||||
use device::{Device, DeviceOwned, DeviceQueueFamilies};
|
||||
|
||||
|
@ -110,7 +110,7 @@ pub enum Error {
|
|||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
type Result<T> = core::result::Result<T, Error>;
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
|
||||
struct VkNameList<'a> {
|
||||
names: Vec<*const i8>,
|
||||
|
@ -1072,7 +1072,7 @@ impl Drop for Surface {
|
|||
}
|
||||
}
|
||||
|
||||
struct SamplerCache {
|
||||
pub struct SamplerCache {
|
||||
device: Device,
|
||||
samplers: HashMap<pipeline::SamplerDesc, pipeline::Sampler>,
|
||||
}
|
||||
|
@ -1101,7 +1101,7 @@ impl SamplerCache {
|
|||
|
||||
pub struct Vulkan {
|
||||
instance: Arc<Instance>,
|
||||
device: Device,
|
||||
pub device: Device,
|
||||
samplers: SamplerCache,
|
||||
}
|
||||
|
||||
|
@ -1124,6 +1124,14 @@ impl Vulkan {
|
|||
const NSIGHT_INTERCEPTION_LAYER_NAME: &'static core::ffi::CStr =
|
||||
c"VK_LAYER_NV_nomad_release_public_2021_4_2";
|
||||
|
||||
pub fn samplers(&self) -> &SamplerCache {
|
||||
&self.samplers
|
||||
}
|
||||
|
||||
pub fn samplers_mut(&mut self) -> &mut SamplerCache {
|
||||
&mut self.samplers
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
app_name: &str,
|
||||
instance_layers: &[&CStr],
|
||||
|
@ -1232,6 +1240,7 @@ impl Vulkan {
|
|||
.features10(
|
||||
vk::PhysicalDeviceFeatures::default()
|
||||
.sampler_anisotropy(true)
|
||||
.fill_mode_non_solid(true)
|
||||
.multi_draw_indirect(true),
|
||||
)
|
||||
.features11(vk::PhysicalDeviceVulkan11Features::default().shader_draw_parameters(true))
|
||||
|
@ -2049,7 +2058,7 @@ pub struct Renderer<W> {
|
|||
// thinkw: want renderer linked with display? then no (real) headless
|
||||
display: RawDisplayHandle,
|
||||
pub window_contexts: HashMap<W, WindowContext>,
|
||||
vulkan: Vulkan,
|
||||
pub vulkan: Vulkan,
|
||||
}
|
||||
|
||||
pub use vk::Extent2D;
|
||||
|
@ -2066,447 +2075,59 @@ impl<W> Renderer<W> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn draw_egui(&mut self, ctx: &egui::Context, output: egui::FullOutput) -> Result<()> {
|
||||
let pool = commands::SingleUseCommandPool::new(
|
||||
self.vulkan.device.clone(),
|
||||
self.vulkan.device.graphics_queue().clone(),
|
||||
)
|
||||
.unwrap();
|
||||
let cmd = pool.alloc().unwrap();
|
||||
|
||||
let cmd_objects = output
|
||||
.textures_delta
|
||||
.set
|
||||
.iter()
|
||||
.map(|(egui_id, delta)| {
|
||||
let size = delta.image.size();
|
||||
let byte_size = size[0] * size[1] * 4;
|
||||
|
||||
let mut staging = buffers::Buffer::new(
|
||||
self.vulkan.device.clone(),
|
||||
buffers::BufferDesc {
|
||||
name: Some(format!("egui-{egui_id:?}-staging-buf").into()),
|
||||
size: byte_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()
|
||||
},
|
||||
)
|
||||
.expect("staging buffer");
|
||||
pub async fn draw_with_graph<K, F, G, T>(
|
||||
&mut self,
|
||||
window: &K,
|
||||
pre_present_cb: F,
|
||||
cb: G,
|
||||
) -> Result<T>
|
||||
where
|
||||
K: core::hash::Hash + Eq,
|
||||
W: core::hash::Hash + Eq + Borrow<K>,
|
||||
F: FnOnce(),
|
||||
G: FnOnce(&mut Self, &mut render_graph::RenderGraph) -> T,
|
||||
{
|
||||
let mut mem = staging.map().expect("mapping staging buffer");
|
||||
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 dev = self.vulkan.device.clone();
|
||||
|
||||
let ctx = self.window_contexts.get(window).unwrap();
|
||||
let (frame, suboptimal) = ctx.current_swapchain.read().clone().acquire_image().await?;
|
||||
|
||||
if suboptimal {
|
||||
tracing::warn!(
|
||||
"swapchain ({:?}) is suboptimal!",
|
||||
ctx.current_swapchain.read().swapchain
|
||||
);
|
||||
}
|
||||
|
||||
let sampled = if delta.is_whole() {
|
||||
vk::ImageUsageFlags::SAMPLED
|
||||
} else {
|
||||
vk::ImageUsageFlags::TRANSFER_SRC
|
||||
};
|
||||
let [r, g, b] =
|
||||
rand::prelude::StdRng::seed_from_u64(ctx.surface.surface.as_raw()).gen::<[f32; 3]>();
|
||||
let clear_color = Rgba([r, g, b, 1.0]);
|
||||
|
||||
let texture = Arc::new(
|
||||
images::Image::new(
|
||||
self.vulkan.device.clone(),
|
||||
images::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: sampled | vk::ImageUsageFlags::TRANSFER_DST,
|
||||
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.expect("image creation"),
|
||||
);
|
||||
let mut rg = render_graph::RenderGraph::new();
|
||||
let framebuffer = rg.import_image(frame.image.clone(), Access::undefined());
|
||||
rg.mark_as_output(framebuffer, Access::present());
|
||||
rg.framebuffer = Some(framebuffer);
|
||||
|
||||
cmd.image_barrier(
|
||||
texture.image(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::empty(),
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
vk::ImageLayout::UNDEFINED,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
None,
|
||||
);
|
||||
cmd.copy_buffer_to_image(
|
||||
staging.buffer(),
|
||||
texture.image(),
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
&[vk::BufferImageCopy {
|
||||
buffer_offset: 0,
|
||||
buffer_row_length: delta.image.width() as u32,
|
||||
buffer_image_height: delta.image.height() as u32,
|
||||
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: vk::Extent3D {
|
||||
width: texture.size().width,
|
||||
height: texture.size().height,
|
||||
depth: 1,
|
||||
},
|
||||
}],
|
||||
);
|
||||
render_graph::clear_pass(&mut rg, clear_color, framebuffer);
|
||||
|
||||
let id = self.egui_state.lookup_texture(*egui_id).unwrap_or_else(|| {
|
||||
let id = texture::TextureId::new();
|
||||
let t = cb(self, &mut rg);
|
||||
|
||||
self.egui_state.textures.insert(
|
||||
*egui_id,
|
||||
EguiTextureInfo {
|
||||
id,
|
||||
options: delta.options,
|
||||
},
|
||||
);
|
||||
let cmds = rg.resolve(dev.clone())?;
|
||||
|
||||
id
|
||||
});
|
||||
|
||||
if let Some(pos) = delta.pos {
|
||||
// SAFETY: must exist because image is not whole.
|
||||
let existing_texture = self.texture_handler.textures.get(&id).cloned().unwrap();
|
||||
|
||||
cmd.image_barrier(
|
||||
texture.image(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_READ,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
vk::ImageLayout::TRANSFER_SRC_OPTIMAL,
|
||||
None,
|
||||
);
|
||||
cmd.image_barrier(
|
||||
existing_texture.handle(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::empty(),
|
||||
vk::AccessFlags2::empty(),
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
vk::ImageLayout::UNDEFINED,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
None,
|
||||
);
|
||||
cmd.blit_images(
|
||||
&texture,
|
||||
util::Rect2D::new(0, 0, texture.width() as i32, texture.height() as i32),
|
||||
&existing_texture,
|
||||
util::Rect2D::new_from_size(
|
||||
glam::ivec2(pos[0] as i32, pos[1] as i32),
|
||||
glam::ivec2(texture.width() as i32, texture.height() as i32),
|
||||
),
|
||||
);
|
||||
cmd.image_barrier(
|
||||
existing_texture.handle(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
vk::PipelineStageFlags2::FRAGMENT_SHADER,
|
||||
vk::AccessFlags2::SHADER_SAMPLED_READ,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||
None,
|
||||
);
|
||||
} else {
|
||||
cmd.image_barrier(
|
||||
texture.handle(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
vk::PipelineStageFlags2::FRAGMENT_SHADER,
|
||||
vk::AccessFlags2::SHADER_SAMPLED_READ,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL,
|
||||
None,
|
||||
);
|
||||
self.texture_handler
|
||||
.insert_image_with_id(id, texture.clone());
|
||||
tracing::trace!("new texture for egui: {egui_id:?} -> {id:?}");
|
||||
}
|
||||
|
||||
(staging, texture)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let draw_data = ctx.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 = self
|
||||
.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 device = self.vulkan.device.clone();
|
||||
let (draw_staging, vertices, indices, draw_calls, texture_ids) = {
|
||||
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 staging_size = vertices_size + indices_size + draw_calls_size;
|
||||
|
||||
let mut staging = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
buffers::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 future = cmds.submit(
|
||||
Some((frame.acquire, vk::PipelineStageFlags::TRANSFER)),
|
||||
Some(frame.release),
|
||||
Arc::new(sync::Fence::create(dev.clone())?),
|
||||
)?;
|
||||
|
||||
{
|
||||
let mut map = staging.map()?;
|
||||
// call pre_present_notify
|
||||
pre_present_cb();
|
||||
|
||||
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));
|
||||
}
|
||||
future.await;
|
||||
let wait = Some(frame.release);
|
||||
frame.present(wait)?;
|
||||
|
||||
let vertices = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
buffers::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 = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
buffers::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 = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
buffers::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()
|
||||
},
|
||||
)?;
|
||||
|
||||
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 mut texture_ids = buffers::Buffer::new(
|
||||
device.clone(),
|
||||
buffers::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 = self.texture_handler.get_texture(entry.id).unwrap();
|
||||
let info = vk::DescriptorImageInfo {
|
||||
sampler: self
|
||||
.vulkan
|
||||
.samplers
|
||||
.get_sampler(entry.into_sampler_desc())
|
||||
.unwrap(),
|
||||
image_view: texture
|
||||
.get_view(images::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(self.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(self.egui_state.descriptor_set)
|
||||
}))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
unsafe {
|
||||
device.dev().update_descriptor_sets(&descriptor_writes, &[]);
|
||||
}
|
||||
|
||||
let to_remove_tex_ids = output
|
||||
.textures_delta
|
||||
.free
|
||||
.iter()
|
||||
.filter_map(|id| self.egui_state.textures.get(id).cloned())
|
||||
.map(|entry| entry.id)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
self.egui_state.render_state = Some(EguiRenderState {
|
||||
vertices,
|
||||
indices,
|
||||
draw_calls,
|
||||
num_draw_calls,
|
||||
texture_ids,
|
||||
textures_to_free: to_remove_tex_ids,
|
||||
});
|
||||
|
||||
let fence = Arc::new(sync::Fence::create(device.clone()).unwrap());
|
||||
let future = cmd.submit_async(None, None, fence).unwrap();
|
||||
|
||||
future.block()?;
|
||||
|
||||
black_box((cmd_objects, draw_staging));
|
||||
// free after drawing
|
||||
Ok(())
|
||||
Ok(t)
|
||||
}
|
||||
|
||||
pub fn debug_draw_egui<K, F>(
|
||||
|
@ -2588,159 +2209,6 @@ impl<W> Renderer<W> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn debug_draw<K, F: FnOnce()>(&mut self, window: &K, pre_present_cb: F) -> Result<()>
|
||||
where
|
||||
K: core::hash::Hash + Eq,
|
||||
W: core::hash::Hash + Eq + Borrow<K>,
|
||||
{
|
||||
let dev = self.vulkan.device.clone();
|
||||
let pool = commands::SingleUseCommandPool::new(dev.clone(), dev.graphics_queue().clone())?;
|
||||
|
||||
if let Some(ctx) = self.window_contexts.get(window) {
|
||||
let (frame, suboptimal) =
|
||||
smol::block_on(ctx.current_swapchain.read().clone().acquire_image())?;
|
||||
|
||||
if suboptimal {
|
||||
tracing::warn!(
|
||||
"swapchain ({:?}) is suboptimal!",
|
||||
ctx.current_swapchain.read().swapchain
|
||||
);
|
||||
}
|
||||
|
||||
let [r, g, b] = rand::prelude::StdRng::seed_from_u64(ctx.surface.surface.as_raw())
|
||||
.gen::<[f32; 3]>();
|
||||
let clear_color = Rgba([r, g, b, 1.0]);
|
||||
|
||||
let egui_ctx = self.egui_state.render_state.take();
|
||||
|
||||
let cmd = util::timed("record command buffer", || {
|
||||
let cmd = pool.alloc()?;
|
||||
cmd.image_barrier(
|
||||
frame.image.handle(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::empty(),
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
vk::ImageLayout::UNDEFINED,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
None,
|
||||
);
|
||||
cmd.clear_color_image(
|
||||
frame.image.handle(),
|
||||
frame.format,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
clear_color,
|
||||
&[images::SUBRESOURCERANGE_COLOR_ALL],
|
||||
);
|
||||
cmd.image_barrier(
|
||||
frame.image.handle(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::TRANSFER,
|
||||
vk::AccessFlags2::TRANSFER_WRITE,
|
||||
vk::PipelineStageFlags2::FRAGMENT_SHADER,
|
||||
vk::AccessFlags2::SHADER_WRITE,
|
||||
vk::ImageLayout::TRANSFER_DST_OPTIMAL,
|
||||
vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
|
||||
None,
|
||||
);
|
||||
|
||||
if let Some(ctx) = egui_ctx.as_ref() {
|
||||
_ = &ctx.texture_ids;
|
||||
|
||||
let color_attachment = &vk::RenderingAttachmentInfo::default()
|
||||
.image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
|
||||
.image_view(frame.view)
|
||||
.load_op(vk::AttachmentLoadOp::LOAD)
|
||||
.store_op(vk::AttachmentStoreOp::STORE);
|
||||
|
||||
cmd.begin_rendering(
|
||||
vk::RenderingInfo::default()
|
||||
.color_attachments(core::slice::from_ref(color_attachment))
|
||||
.layer_count(1)
|
||||
.render_area(vk::Rect2D::default().extent(frame.swapchain.extent)),
|
||||
);
|
||||
|
||||
cmd.set_scissors(&[vk::Rect2D::default()
|
||||
.offset(vk::Offset2D::default())
|
||||
.extent(frame.swapchain.extent)]);
|
||||
|
||||
cmd.set_viewport(&[vk::Viewport::default()
|
||||
.x(0.0)
|
||||
.y(0.0)
|
||||
.min_depth(0.0)
|
||||
.max_depth(1.0)
|
||||
.width(frame.swapchain.extent.width as f32)
|
||||
.height(frame.swapchain.extent.height as f32)]);
|
||||
|
||||
cmd.bind_pipeline(&self.egui_state.pipeline);
|
||||
cmd.bind_indices(ctx.indices.buffer(), 0, vk::IndexType::UINT32);
|
||||
cmd.bind_vertices(ctx.vertices.buffer(), 0);
|
||||
cmd.push_constants(
|
||||
&self.egui_state.pipeline_layout,
|
||||
vk::ShaderStageFlags::VERTEX,
|
||||
0,
|
||||
bytemuck::cast_slice(
|
||||
&[
|
||||
frame.swapchain.extent.width as f32,
|
||||
frame.swapchain.extent.height as f32,
|
||||
]
|
||||
.map(|f| f.to_bits()),
|
||||
),
|
||||
);
|
||||
cmd.bind_descriptor_sets(
|
||||
&self.egui_state.pipeline_layout,
|
||||
vk::PipelineBindPoint::GRAPHICS,
|
||||
&[self.egui_state.descriptor_set],
|
||||
);
|
||||
cmd.draw_indexed_indirect(
|
||||
ctx.draw_calls.buffer(),
|
||||
0,
|
||||
ctx.num_draw_calls as u32,
|
||||
size_of::<vk::DrawIndexedIndirectCommand>() as u32,
|
||||
);
|
||||
|
||||
cmd.end_rendering();
|
||||
}
|
||||
|
||||
cmd.image_barrier(
|
||||
frame.image.handle(),
|
||||
vk::ImageAspectFlags::COLOR,
|
||||
vk::PipelineStageFlags2::FRAGMENT_SHADER,
|
||||
vk::AccessFlags2::SHADER_WRITE,
|
||||
vk::PipelineStageFlags2::BOTTOM_OF_PIPE,
|
||||
vk::AccessFlags2::empty(),
|
||||
vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL,
|
||||
vk::ImageLayout::PRESENT_SRC_KHR,
|
||||
None,
|
||||
);
|
||||
|
||||
Result::Ok(cmd)
|
||||
})?;
|
||||
|
||||
let future = cmd.submit_async(
|
||||
Some((frame.acquire, vk::PipelineStageFlags::TRANSFER)),
|
||||
Some(frame.release),
|
||||
Arc::new(sync::Fence::create(dev.clone())?),
|
||||
)?;
|
||||
|
||||
// call pre_present_notify
|
||||
pre_present_cb();
|
||||
|
||||
let wait = Some(frame.release);
|
||||
frame.present(wait)?;
|
||||
future.block()?;
|
||||
|
||||
egui_ctx.map(|ctx| {
|
||||
for id in ctx.textures_to_free {
|
||||
self.texture_handler.remove_texture(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new_window_context(
|
||||
&mut self,
|
||||
extent: vk::Extent2D,
|
||||
|
|
|
@ -43,7 +43,7 @@ impl From<GraphResourceDesc> for GraphResource {
|
|||
|
||||
#[derive(Default, Debug, PartialEq, Eq)]
|
||||
pub enum GraphResource {
|
||||
Framebuffer(Arc<SwapchainFrame>),
|
||||
Framebuffer(Arc<Image>),
|
||||
ImportedImage(Arc<Image>),
|
||||
ImportedBuffer(Arc<Buffer>),
|
||||
Image(Arc<Image>),
|
||||
|
@ -63,7 +63,7 @@ impl GraphResource {
|
|||
|
||||
match self {
|
||||
GraphResource::Framebuffer(swapchain_frame) => {
|
||||
(swapchain_frame.index, swapchain_frame.image.handle()).hash(&mut state)
|
||||
(swapchain_frame.handle()).hash(&mut state)
|
||||
}
|
||||
GraphResource::ImportedImage(image) => image.handle().hash(&mut state),
|
||||
GraphResource::ImportedBuffer(buffer) => buffer.handle().hash(&mut state),
|
||||
|
@ -95,6 +95,7 @@ pub struct RenderContext<'a> {
|
|||
pub device: device::Device,
|
||||
pub cmd: commands::SingleUseCommand,
|
||||
pub resources: &'a [GraphResource],
|
||||
pub framebuffer: Option<GraphResourceId>,
|
||||
}
|
||||
|
||||
impl RenderContext<'_> {
|
||||
|
@ -102,7 +103,7 @@ impl RenderContext<'_> {
|
|||
self.resources.get(id.0 as usize).and_then(|res| match res {
|
||||
GraphResource::ImportedImage(arc) => Some(arc),
|
||||
GraphResource::Image(image) => Some(image),
|
||||
GraphResource::Framebuffer(fb) => Some(&fb.image),
|
||||
GraphResource::Framebuffer(fb) => Some(fb),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
@ -113,6 +114,14 @@ impl RenderContext<'_> {
|
|||
_ => None,
|
||||
})
|
||||
}
|
||||
pub fn get_framebuffer(&self) -> Option<&Image> {
|
||||
self.framebuffer
|
||||
.and_then(|rid| self.resources.get(rid.0 as usize))
|
||||
.and_then(|res| match res {
|
||||
GraphResource::Framebuffer(arc) => Some(arc.as_ref()),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
|
@ -349,6 +358,7 @@ pub struct RenderGraph {
|
|||
/// the rendergraph produces these resources. Any passes on which these
|
||||
/// outputs do not depend are pruned.
|
||||
outputs: BTreeMap<GraphResourceId, Access>,
|
||||
pub(crate) framebuffer: Option<GraphResourceId>,
|
||||
}
|
||||
|
||||
impl RenderGraph {
|
||||
|
@ -360,9 +370,14 @@ impl RenderGraph {
|
|||
resources: Vec::new(),
|
||||
pass_descs,
|
||||
outputs: BTreeMap::new(),
|
||||
framebuffer: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_framebuffer(&self) -> Option<GraphResourceId> {
|
||||
self.framebuffer
|
||||
}
|
||||
|
||||
fn get_next_resource_id(&mut self) -> GraphResourceId {
|
||||
GraphResourceId(self.resources.len() as u32)
|
||||
}
|
||||
|
@ -406,8 +421,14 @@ impl RenderGraph {
|
|||
self.import_resource(res, access)
|
||||
}
|
||||
|
||||
pub fn import_framebuffer(&mut self, frame: Arc<SwapchainFrame>) -> GraphResourceId {
|
||||
self.import_resource(GraphResource::Framebuffer(frame), Access::undefined())
|
||||
pub fn import_framebuffer(&mut self, frame: &SwapchainFrame) -> GraphResourceId {
|
||||
let rid = self.import_resource(
|
||||
GraphResource::Framebuffer(frame.image.clone()),
|
||||
Access::undefined(),
|
||||
);
|
||||
self.mark_as_output(rid, Access::present());
|
||||
self.framebuffer = Some(rid);
|
||||
rid
|
||||
}
|
||||
|
||||
pub fn add_pass(&mut self, pass: PassDesc) {
|
||||
|
@ -500,6 +521,7 @@ impl RenderGraph {
|
|||
device: device.clone(),
|
||||
cmd,
|
||||
resources,
|
||||
framebuffer: self.framebuffer,
|
||||
};
|
||||
|
||||
for pass in passes {
|
||||
|
@ -538,7 +560,7 @@ impl RenderGraph {
|
|||
) {
|
||||
let barrier: Barrier = match res {
|
||||
GraphResource::Framebuffer(arc) => {
|
||||
image_barrier(arc.image.handle(), arc.image.format(), from, to, None).into()
|
||||
image_barrier(arc.handle(), arc.format(), from, to, None).into()
|
||||
}
|
||||
GraphResource::ImportedImage(arc) => {
|
||||
image_barrier(arc.handle(), arc.format(), from, to, None).into()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use ash::vk;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! def_monotonic_id {
|
||||
|
@ -350,8 +351,13 @@ pub fn timed<T, F: FnOnce() -> T>(label: &str, f: F) -> T {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
#[repr(transparent)]
|
||||
pub struct Rgba(pub [f32; 4]);
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod, Zeroable)]
|
||||
#[repr(transparent)]
|
||||
pub struct Rgba8(pub [u8; 4]);
|
||||
|
||||
impl std::hash::Hash for Rgba {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.map(|f| hash_f32(state, f));
|
||||
|
@ -369,6 +375,9 @@ impl Rgba {
|
|||
pub fn into_f32(&self) -> [f32; 4] {
|
||||
self.0
|
||||
}
|
||||
pub fn into_u8(&self) -> Rgba8 {
|
||||
Rgba8(self.0.map(|f| (f.clamp(0.0, 1.0) * 255.0) as u8))
|
||||
}
|
||||
pub fn into_snorm(&self) -> [f32; 4] {
|
||||
self.0.map(|f| (f - 0.5) * 2.0)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue