vidya/crates/renderer/src/rendering/mod.rs

389 lines
14 KiB
Rust

use std::sync::Arc;
use ash::vk;
use glam::{f32::Mat4, vec3};
pub use crate::egui_pass::{egui_pass, egui_pre_pass};
use crate::{
Result,
buffers::{Buffer, BufferDesc},
commands::{self, traits::CommandBufferExt},
device::{Device, DeviceOwned},
images::ImageViewDesc,
pipeline,
render_graph::{
Access, GraphResourceId, PassDesc, RecordFn, RenderContext, RenderGraph, buffer_barrier,
},
sync,
util::Rgba8,
};
pub struct Wireframe {
positions: Arc<Buffer>,
indices: Arc<Buffer>,
num_indices: u32,
colors: Arc<Buffer>,
pipeline: Arc<pipeline::Pipeline>,
layout: Arc<pipeline::PipelineLayout>,
}
impl Wireframe {
pub async fn from_triangles_indexed(
dev: Device,
positions: Vec<glam::Vec3>,
indices: Vec<u32>,
colors: Vec<Rgba8>,
) -> Result<Self> {
let positions_size = positions.len() * size_of::<glam::Vec3>();
let num_indices = indices.len() as u32;
let indices_size = indices.len() * size_of::<u32>();
let indices_offset = positions_size;
let colors_size = colors.len() * size_of::<Rgba8>();
let colors_offset = indices_offset + indices_size;
let staging_size = positions_size + indices_size + colors_size;
let mut staging = Buffer::new(
dev.clone(),
BufferDesc {
name: Some("wireframe-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()?;
map[..positions_size].copy_from_slice(bytemuck::cast_slice(&positions));
map[indices_offset..][..indices_size].copy_from_slice(bytemuck::cast_slice(&indices));
map[colors_offset..][..colors_size].copy_from_slice(bytemuck::cast_slice(&colors));
}
let positions = Buffer::new(
dev.clone(),
BufferDesc {
name: Some("wireframe-positions".into()),
size: positions_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default()
},
)?;
let indices = Buffer::new(
dev.clone(),
BufferDesc {
name: Some("wireframe-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 colors = Buffer::new(
dev.clone(),
BufferDesc {
name: Some("wireframe-colors".into()),
size: colors_size as u64,
usage: vk::BufferUsageFlags::TRANSFER_DST | vk::BufferUsageFlags::VERTEX_BUFFER,
mem_usage: vk_mem::MemoryUsage::AutoPreferDevice,
..Default::default()
},
)?;
let pool = commands::SingleUseCommandPool::new(dev.clone(), dev.main_queue().clone())?;
let cmd = pool.alloc()?;
cmd.copy_buffers(
staging.handle(),
positions.handle(),
&[vk::BufferCopy {
src_offset: 0,
dst_offset: 0,
size: positions_size as u64,
}],
);
cmd.copy_buffers(
staging.handle(),
indices.handle(),
&[vk::BufferCopy {
src_offset: indices_offset as u64,
dst_offset: 0,
size: indices_size as u64,
}],
);
cmd.copy_buffers(
staging.handle(),
colors.handle(),
&[vk::BufferCopy {
src_offset: colors_offset as u64,
dst_offset: 0,
size: colors_size as u64,
}],
);
let barriers = [
buffer_barrier(
positions.handle(),
0,
positions.len(),
Access::transfer_write(),
Access::vertex_read(),
None,
),
buffer_barrier(
indices.handle(),
0,
indices.len(),
Access::transfer_write(),
Access::index_read(),
None,
),
buffer_barrier(
colors.handle(),
0,
colors.len(),
Access::transfer_write(),
Access::vertex_read(),
None,
),
];
unsafe {
dev.dev().cmd_pipeline_barrier2(
cmd.buffer(),
&vk::DependencyInfo::default().buffer_memory_barriers(&barriers),
);
}
let future = cmd.submit_async(
None,
None,
Arc::new(sync::Fence::from_pool(&dev.pools.fences, None)?),
)?;
let (pipeline, layout) = Self::create_pipeline(dev.clone())?;
future.await;
Ok(Self {
positions: Arc::new(positions),
indices: Arc::new(indices),
colors: Arc::new(colors),
pipeline: Arc::new(pipeline),
layout: Arc::new(layout),
num_indices,
})
}
fn create_pipeline(device: Device) -> Result<(pipeline::Pipeline, pipeline::PipelineLayout)> {
let pipeline_layout = pipeline::PipelineLayout::new(
device.clone(),
pipeline::PipelineLayoutDesc {
descriptor_set_layouts: &[],
push_constant_ranges: &[vk::PushConstantRange {
offset: 0,
size: 128,
stage_flags: vk::ShaderStageFlags::VERTEX,
}],
name: Some("wireframe-pipeline-layout".into()),
},
)?;
let shader = pipeline::ShaderModule::new_from_path(
device.clone(),
"crates/renderer/shaders/wireframe.spv",
)?;
let pipeline = pipeline::Pipeline::new(
device.clone(),
pipeline::PipelineDesc::Graphics(pipeline::GraphicsPipelineDesc {
flags: Default::default(),
name: Some("wireframe-pipeline".into()),
shader_stages: &[
pipeline::ShaderStageDesc {
flags: vk::PipelineShaderStageCreateFlags::empty(),
module: &shader,
stage: vk::ShaderStageFlags::FRAGMENT,
entry: c"main".into(),
},
pipeline::ShaderStageDesc {
flags: vk::PipelineShaderStageCreateFlags::empty(),
module: &shader,
stage: vk::ShaderStageFlags::VERTEX,
entry: c"main".into(),
},
],
render_pass: None,
layout: &pipeline_layout,
subpass: None,
base_pipeline: None,
vertex_input: Some(pipeline::VertexInputState {
bindings: &[
vk::VertexInputBindingDescription {
binding: 0,
stride: size_of::<glam::Vec3>() as u32,
input_rate: vk::VertexInputRate::VERTEX,
},
vk::VertexInputBindingDescription {
binding: 1,
stride: size_of::<Rgba8>() as u32,
input_rate: vk::VertexInputRate::VERTEX,
},
],
attributes: &[
vk::VertexInputAttributeDescription {
location: 0,
binding: 0,
format: vk::Format::R32G32B32_SFLOAT,
offset: 0,
},
vk::VertexInputAttributeDescription {
location: 1,
binding: 1,
format: vk::Format::R8G8B8A8_UNORM,
offset: 0,
},
],
}),
input_assembly: Some(pipeline::InputAssemblyState {
topology: vk::PrimitiveTopology::TRIANGLE_LIST,
primitive_restart: false,
}),
tessellation: None,
viewport: Some(pipeline::ViewportState {
num_viewports: 1,
num_scissors: 1,
..Default::default()
}),
rasterization: Some(pipeline::RasterizationState {
cull_mode: vk::CullModeFlags::NONE,
polygon_mode: vk::PolygonMode::LINE,
..Default::default()
}),
multisample: Some(pipeline::MultisampleState {
..Default::default()
}),
depth_stencil: Some(pipeline::DepthStencilState {
depth: Some(pipeline::DepthState {
write_enable: false,
compare_op: Some(vk::CompareOp::LESS),
bounds: Some(pipeline::DepthBounds { min: 0.0, max: 1.0 }),
}),
..Default::default()
}),
color_blend: Some(pipeline::ColorBlendState {
attachments: &[vk::PipelineColorBlendAttachmentState::default()
.color_write_mask(vk::ColorComponentFlags::RGBA)
.blend_enable(true)
.color_blend_op(vk::BlendOp::ADD)
.src_color_blend_factor(vk::BlendFactor::ONE)
.dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)
.alpha_blend_op(vk::BlendOp::ADD)
.src_alpha_blend_factor(vk::BlendFactor::ONE)
.dst_alpha_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)],
..Default::default()
}),
rendering: Some(pipeline::RenderingState {
color_formats: &[vk::Format::R8G8B8A8_UNORM],
..Default::default()
}),
dynamic: Some(pipeline::DynamicState {
dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
..Default::default()
}),
}),
)?;
Ok((pipeline, pipeline_layout))
}
pub fn pass(&self, rg: &mut RenderGraph, target: GraphResourceId) -> Result<()> {
let reads = [(target, Access::color_attachment_read_write())].to_vec();
let writes = [(target, Access::color_attachment_write_only())].to_vec();
let record: Box<RecordFn> = Box::new({
let positions = self.positions.clone();
let indices = self.indices.clone();
let colors = self.colors.clone();
let num_indices = self.num_indices;
let pipeline = self.pipeline.clone();
let layout = self.layout.clone();
move |ctx: &RenderContext| -> Result<()> {
let target = ctx.get_image(target).unwrap();
let cmd = &ctx.cmd;
//let model = Mat4::from_scale(vec3(0.01, 0.01, 0.01));
let proj = Mat4::perspective_lh(
core::f32::consts::FRAC_PI_4,
target.width() as f32 / target.height() as f32,
0.1,
100.0,
);
let pos = vec3(0.0, 0.0, -5.0);
let view = Mat4::look_at_rh(pos, pos + vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 0.0));
let to_clip = proj * view; // * model;
let color_attachment = &vk::RenderingAttachmentInfo::default()
.image_layout(vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL)
.image_view(target.get_view(ImageViewDesc {
kind: vk::ImageViewType::TYPE_2D,
format: target.format(),
aspect: vk::ImageAspectFlags::COLOR,
..Default::default()
})?)
.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(target.extent_2d())),
);
cmd.set_scissors(&[vk::Rect2D::default()
.offset(vk::Offset2D::default())
.extent(target.extent_2d())]);
cmd.set_viewport(&[vk::Viewport::default()
.x(0.0)
.y(0.0)
.min_depth(0.0)
.max_depth(1.0)
.width(target.width() as f32)
.height(target.height() as f32)]);
cmd.bind_pipeline(&pipeline);
cmd.bind_indices(indices.buffer(), 0, vk::IndexType::UINT32);
cmd.bind_vertex_buffers(&[positions.handle(), colors.handle()], &[0, 0]);
cmd.push_constants(
&layout,
vk::ShaderStageFlags::VERTEX,
0,
bytemuck::cast_slice(&[to_clip]),
);
cmd.draw_indexed(num_indices, 1, 0, 0, 0);
cmd.end_rendering();
Ok(())
}
});
rg.add_pass(PassDesc {
reads,
writes,
record: Some(record),
});
Ok(())
}
}