This commit is contained in:
Janis 2024-12-30 04:56:07 +01:00
parent f0fff72bce
commit 81f1ee1f96
8 changed files with 579 additions and 3 deletions

View file

@ -0,0 +1,8 @@
#!/bin/bash
set -e
SLANGC="/opt/shader-slang-bin/bin/slangc"
$SLANGC egui.slang -profile glsl_450 -target spirv -o egui_vert.spv -entry vertex
$SLANGC egui.slang -profile glsl_450 -target spirv -o egui_frag.spv -entry fragment

View file

@ -0,0 +1,48 @@
struct Fragment {
float4 color : SV_Target;
}
struct VertexIn {
[[vk::layout(0)]] float2 pos;
[[vk::layout(1)]] float2 uv;
[[vk::layout(2)]] float4 color;
}
struct VertexOut {
[[vk::layout(0)]] float4 color;
[[vk::layout(1)]] float2 uv;
float4 position : SV_Position;
}
struct PushConstant {
float2 screen_size;
}
[[vk::push_constant]]
ConstantBuffer<PushConstant> push_constant;
[shader("vertex")]
VertexOut vertex(VertexIn vertex) {
VertexOut output;
output.position = float4(
2.0 * vertex.pos.x / push_constant.screen_size.x - 1.0,
2.0 * vertex.pos.y / push_constant.screen_size.y - 1.0,
0.0,
1.0,
);
output.color = vertex.color;
output.uv = vertex.uv;
return output;
}
[[vk::binding(0)]]
Sampler2D texture;
[shader("fragment")]
Fragment fragment(VertexOut input) {
Fragment output;
output.color = input.color * texture.Sample(input.uv);
return output;
}

Binary file not shown.

Binary file not shown.

View file

@ -227,6 +227,22 @@ impl SingleUseCommand {
} }
} }
pub fn begin_rendering(&self, rendering_info: vk::RenderingInfo<'_>) {
unsafe {
self.device
.dev()
.cmd_begin_rendering(self.buffer(), &rendering_info);
}
}
// pub fn
pub fn end_rendering(&self) {
unsafe {
self.device.dev().cmd_end_rendering(self.buffer());
}
}
pub fn submit_fence( pub fn submit_fence(
&self, &self,
wait: Option<(vk::Semaphore, vk::PipelineStageFlags)>, wait: Option<(vk::Semaphore, vk::PipelineStageFlags)>,

View file

@ -1,6 +1,10 @@
use std::{borrow::Cow, collections::BTreeMap, ops::Deref, sync::Arc}; use std::{borrow::Cow, collections::BTreeMap, ops::Deref, sync::Arc};
use ash::{khr, prelude::VkResult, vk}; use ash::{
khr,
prelude::VkResult,
vk::{self, Handle},
};
use parking_lot::Mutex; use parking_lot::Mutex;
use tinyvec::{array_vec, ArrayVec}; use tinyvec::{array_vec, ArrayVec};
@ -273,8 +277,20 @@ pub struct DeviceOwnedDebugObject<T> {
name: Option<Cow<'static, str>>, name: Option<Cow<'static, str>>,
} }
impl<T: std::fmt::Debug + vk::Handle + Copy> std::fmt::Debug for DeviceOwnedDebugObject<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct(core::any::type_name::<T>())
.field_with("device", |f| {
write!(f, "0x{:x}", self.device.0.device.handle().as_raw())
})
.field_with("handle", |f| write!(f, "0x{:x}", &self.object.as_raw()))
.field("name", &self.name)
.finish()
}
}
impl<T> DeviceOwnedDebugObject<T> { impl<T> DeviceOwnedDebugObject<T> {
fn new<S: Into<Cow<'static, str>>>( pub fn new<S: Into<Cow<'static, str>>>(
device: crate::Device, device: crate::Device,
object: T, object: T,
name: Option<S>, name: Option<S>,

View file

@ -3,7 +3,8 @@
closure_lifetime_binder, closure_lifetime_binder,
let_chains, let_chains,
negative_impls, negative_impls,
map_try_insert map_try_insert,
debug_closure_helpers
)] )]
#![allow(unused)] #![allow(unused)]
use std::{ use std::{
@ -38,6 +39,7 @@ mod buffers;
mod commands; mod commands;
mod device; mod device;
mod images; mod images;
mod pipeline;
mod render_graph; mod render_graph;
mod sync; mod sync;
mod util; mod util;

View file

@ -0,0 +1,486 @@
use std::{borrow::Cow, path::Path, sync::Arc};
use ash::{prelude::*, vk};
use crate::device::{Device, DeviceOwnedDebugObject};
#[derive(Debug, Default)]
pub struct ShaderStageDesc<'a> {
pub flags: vk::PipelineShaderStageCreateFlags,
pub module: vk::ShaderModule,
pub stage: vk::ShaderStageFlags,
pub entry: Cow<'a, std::ffi::CStr>,
// specialization: Option<vk::SpecializationInfo>
}
#[derive(Debug, Default)]
pub struct DescriptorSetLayoutBindingDesc {
pub binding: u32,
pub count: u32,
pub kind: vk::DescriptorType,
pub stage: vk::ShaderStageFlags,
}
#[derive(Debug, Default)]
pub struct DescriptorSetLayoutDesc<'a> {
pub flags: vk::DescriptorSetLayoutCreateFlags,
pub bindings: &'a [DescriptorSetLayoutBindingDesc],
pub name: Option<Cow<'static, str>>,
}
#[derive(Debug, Default)]
pub struct PipelineLayoutDesc<'a> {
pub descriptor_set_layouts: &'a [Arc<DescriptorSetLayout>],
pub push_constant_ranges: &'a [vk::PushConstantRange],
pub name: Option<Cow<'static, str>>,
}
#[derive(Debug)]
pub enum PipelineDesc<'a> {
Compute(ComputePipelineDesc<'a>),
Graphics(GraphicsPipelineDesc<'a>),
}
impl PipelineDesc<'_> {
fn name(self) -> Option<Cow<'static, str>> {
match self {
PipelineDesc::Compute(desc) => desc.name,
PipelineDesc::Graphics(desc) => desc.name,
}
}
}
#[derive(Debug)]
pub struct ComputePipelineDesc<'a> {
pub flags: vk::PipelineCreateFlags,
pub name: Option<Cow<'static, str>>,
pub shader_stage: ShaderStageDesc<'a>,
pub layout: Arc<PipelineLayout>,
pub base_pipeline: Option<Arc<Pipeline>>,
}
#[derive(Debug, Default)]
pub struct VertexInputState<'a> {
// pub flags: vk::PipelineVertexInputStateCreateFlags,
pub bindings: &'a [vk::VertexInputBindingDescription],
pub attributes: &'a [vk::VertexInputAttributeDescription],
}
#[derive(Debug, Default)]
pub struct TessellationState {
pub flags: vk::PipelineTessellationStateCreateFlags,
pub patch_control_points: u32,
}
#[derive(Debug, Default)]
pub struct InputAssemblyState {
// pub flags: vk::PipelineInputAssemblyStateCreateFlags,
pub topology: vk::PrimitiveTopology,
pub primitive_restart: bool,
}
#[derive(Debug, Default)]
pub struct ViewportState<'a> {
pub num_scissors: u32,
pub scissors: Option<&'a [vk::Rect2D]>,
pub num_viewports: u32,
pub viewports: Option<&'a [vk::Viewport]>,
}
#[derive(Debug, Default)]
pub struct DepthBiasState {
pub clamp: f32,
pub constant_factor: f32,
pub slope_factor: f32,
}
#[derive(Debug)]
pub struct RasterizationState {
pub depth_clamp_enable: bool,
pub discard_enable: bool,
pub line_width: f32,
pub cull_mode: vk::CullModeFlags,
pub depth_bias: Option<DepthBiasState>,
pub polygon_mode: vk::PolygonMode,
}
impl Default for RasterizationState {
fn default() -> Self {
Self {
depth_clamp_enable: false,
line_width: 1.0,
cull_mode: vk::CullModeFlags::BACK,
depth_bias: Default::default(),
polygon_mode: vk::PolygonMode::FILL,
discard_enable: false,
}
}
}
#[derive(Debug, Default)]
pub struct MultisampleState<'a> {
pub flags: vk::PipelineMultisampleStateCreateFlags,
pub sample_shading_enable: bool,
pub rasterization_samples: vk::SampleCountFlags,
pub min_sample_shading: f32,
pub sample_mask: &'a [vk::SampleMask],
pub alpha_to_coverage_enable: bool,
pub alpha_to_one_enable: bool,
}
#[derive(Debug)]
pub struct DepthBounds {
pub min: f32,
pub max: f32,
}
#[derive(Debug, Default)]
pub struct DepthState {
pub write_enable: bool,
/// sets depthTestEnable to true when `Some`
pub compare_op: Option<vk::CompareOp>,
/// sets depthBoundsTestEnable to true when `Some`
pub bounds: Option<DepthBounds>,
}
#[derive(Debug, Default)]
pub struct StencilState {
pub front: vk::StencilOpState,
pub back: vk::StencilOpState,
}
#[derive(Debug, Default)]
pub struct DepthStencilState {
pub flags: vk::PipelineDepthStencilStateCreateFlags,
pub depth: Option<DepthState>,
pub stencil: Option<StencilState>,
}
#[derive(Debug, Default)]
pub struct ColorBlendState<'a> {
pub flags: vk::PipelineColorBlendStateCreateFlags,
pub attachments: &'a [vk::PipelineColorBlendAttachmentState],
pub logic_op: Option<vk::LogicOp>,
pub blend_constants: [f32; 4],
}
#[derive(Debug, Default)]
pub struct DynamicState<'a> {
pub flags: vk::PipelineDynamicStateCreateFlags,
pub dynamic_states: &'a [vk::DynamicState],
}
#[derive(Debug)]
pub struct GraphicsPipelineDesc<'a> {
pub flags: vk::PipelineCreateFlags,
pub name: Option<Cow<'static, str>>,
pub shader_stages: &'a [ShaderStageDesc<'a>],
pub render_pass: Option<vk::RenderPass>,
pub layout: Arc<PipelineLayout>,
pub subpass: Option<u32>,
pub base_pipeline: Option<Arc<Pipeline>>,
pub vertex_input: Option<VertexInputState<'a>>,
pub input_assembly: Option<InputAssemblyState>,
pub tessellation: Option<TessellationState>,
pub viewport: Option<ViewportState<'a>>,
pub rasterization: Option<RasterizationState>,
pub multisample: Option<MultisampleState<'a>>,
pub depth_stencil: Option<DepthStencilState>,
pub color_blend: Option<ColorBlendState<'a>>,
pub dynamic: Option<DynamicState<'a>>,
}
#[derive(Debug)]
pub struct DescriptorSetLayout {
set_layout: DeviceOwnedDebugObject<vk::DescriptorSetLayout>,
}
impl Drop for DescriptorSetLayout {
fn drop(&mut self) {
unsafe {
self.set_layout
.dev()
.dev()
.destroy_descriptor_set_layout(self.set_layout.handle(), None);
}
}
}
impl DescriptorSetLayout {
pub fn new(device: Device, desc: DescriptorSetLayoutDesc) -> VkResult<Self> {
let bindings = desc
.bindings
.iter()
.map(|binding| {
vk::DescriptorSetLayoutBinding::default()
.binding(binding.binding)
.descriptor_count(binding.count)
.descriptor_type(binding.kind)
.stage_flags(binding.stage)
})
.collect::<Vec<_>>();
let info = &vk::DescriptorSetLayoutCreateInfo::default()
.bindings(&bindings)
.flags(desc.flags);
let layout = unsafe { device.dev().create_descriptor_set_layout(info, None)? };
Ok(Self {
set_layout: DeviceOwnedDebugObject::new(device, layout, desc.name)?,
})
}
}
#[derive(Debug)]
pub struct PipelineLayout {
pipeline_layout: DeviceOwnedDebugObject<vk::PipelineLayout>,
}
impl Drop for PipelineLayout {
fn drop(&mut self) {
unsafe {
self.pipeline_layout
.dev()
.dev()
.destroy_pipeline_layout(self.pipeline_layout.handle(), None);
}
}
}
impl PipelineLayout {
pub fn new(device: Device, desc: PipelineLayoutDesc) -> VkResult<Self> {
let set_layouts = desc
.descriptor_set_layouts
.iter()
.map(|desc| desc.set_layout.handle())
.collect::<Vec<_>>();
let info = &vk::PipelineLayoutCreateInfo::default()
.set_layouts(&set_layouts)
.push_constant_ranges(desc.push_constant_ranges);
let layout = unsafe { device.dev().create_pipeline_layout(info, None)? };
Ok(Self {
pipeline_layout: DeviceOwnedDebugObject::new(device, layout, desc.name)?,
})
}
}
#[derive(Debug)]
pub struct Pipeline {
pipeline: DeviceOwnedDebugObject<vk::Pipeline>,
}
impl Drop for Pipeline {
fn drop(&mut self) {
unsafe {
self.pipeline
.dev()
.dev()
.destroy_pipeline(self.pipeline.handle(), None);
}
}
}
impl ShaderStageDesc<'_> {
fn into_create_info(&self) -> vk::PipelineShaderStageCreateInfo {
vk::PipelineShaderStageCreateInfo::default()
.module(self.module)
.flags(self.flags)
.stage(self.stage)
.name(&self.entry)
}
}
impl Pipeline {
pub fn new(device: Device, desc: PipelineDesc) -> VkResult<Self> {
let name: Option<Cow<'static, str>>;
let result = match desc {
PipelineDesc::Compute(desc) => {
name = desc.name;
let info = &vk::ComputePipelineCreateInfo::default()
.layout(desc.layout.pipeline_layout.handle())
.stage(desc.shader_stage.into_create_info());
unsafe {
device.dev().create_compute_pipelines(
vk::PipelineCache::null(),
core::slice::from_ref(info),
None,
)
}
}
PipelineDesc::Graphics(desc) => {
name = desc.name;
let stages = desc
.shader_stages
.iter()
.map(|stage| stage.into_create_info())
.collect::<Vec<_>>();
let vertex_input = desc.vertex_input.map(|vertex| {
vk::PipelineVertexInputStateCreateInfo::default()
.vertex_attribute_descriptions(vertex.attributes)
.vertex_binding_descriptions(vertex.bindings)
});
let input_assembly = desc.input_assembly.map(|state| {
vk::PipelineInputAssemblyStateCreateInfo::default()
.primitive_restart_enable(state.primitive_restart)
.topology(state.topology)
});
let tessellation = desc.tessellation.map(|state| {
vk::PipelineTessellationStateCreateInfo::default()
.flags(state.flags)
.patch_control_points(state.patch_control_points)
});
let viewport = desc.viewport.map(|state| {
let mut info = vk::PipelineViewportStateCreateInfo::default()
.scissor_count(state.num_scissors)
.viewport_count(state.num_viewports);
if let Some(viewports) = state.viewports {
info = info.viewports(viewports);
}
if let Some(scissors) = state.scissors {
info = info.scissors(scissors);
}
info
});
let rasterization = desc.rasterization.map(|state| {
let mut info = vk::PipelineRasterizationStateCreateInfo::default()
.line_width(state.line_width)
.cull_mode(state.cull_mode)
.polygon_mode(state.polygon_mode)
.rasterizer_discard_enable(state.discard_enable)
.depth_clamp_enable(state.depth_clamp_enable);
if let Some(depth_bias) = state.depth_bias {
info = info
.depth_bias_enable(true)
.depth_bias_clamp(depth_bias.clamp)
.depth_bias_constant_factor(depth_bias.constant_factor)
.depth_bias_slope_factor(depth_bias.slope_factor);
}
info
});
let multisample = desc.multisample.map(|state| {
let mut info = vk::PipelineMultisampleStateCreateInfo::default()
.flags(state.flags)
.min_sample_shading(state.min_sample_shading)
.rasterization_samples(state.rasterization_samples)
.sample_mask(state.sample_mask)
.alpha_to_coverage_enable(state.alpha_to_coverage_enable)
.alpha_to_one_enable(state.alpha_to_one_enable);
info
});
let color_blend = desc.color_blend.map(|state| {
let mut info = vk::PipelineColorBlendStateCreateInfo::default()
.flags(state.flags)
.attachments(state.attachments)
.blend_constants(state.blend_constants)
.logic_op(state.logic_op.unwrap_or(Default::default()))
.logic_op_enable(state.logic_op.is_some());
info
});
let depth_stencil = desc.depth_stencil.map(|state| {
let mut info =
vk::PipelineDepthStencilStateCreateInfo::default().flags(state.flags);
if let Some(depth) = state.depth {
info = info
.depth_compare_op(depth.compare_op.unwrap_or(vk::CompareOp::default()))
.depth_test_enable(depth.compare_op.is_some())
.depth_write_enable(depth.write_enable)
.depth_bounds_test_enable(depth.bounds.is_some());
if let Some(bounds) = depth.bounds {
info = info
.max_depth_bounds(bounds.max)
.min_depth_bounds(bounds.min);
}
}
if let Some(stencil) = state.stencil {
info = info
.stencil_test_enable(true)
.front(stencil.front)
.back(stencil.back);
}
info
});
let dynamic = desc.dynamic.map(|state| {
let mut info = vk::PipelineDynamicStateCreateInfo::default()
.flags(state.flags)
.dynamic_states(state.dynamic_states);
info
});
fn option_to_ptr<T>(option: &Option<T>) -> *const T {
option
.as_ref()
.map(|t| t as *const T)
.unwrap_or(core::ptr::null())
}
let info = &vk::GraphicsPipelineCreateInfo {
flags: desc.flags,
stage_count: stages.len() as u32,
p_stages: stages.as_ptr(),
p_vertex_input_state: option_to_ptr(&vertex_input),
p_input_assembly_state: option_to_ptr(&input_assembly),
p_tessellation_state: option_to_ptr(&tessellation),
p_viewport_state: option_to_ptr(&viewport),
p_rasterization_state: option_to_ptr(&rasterization),
p_multisample_state: option_to_ptr(&multisample),
p_depth_stencil_state: option_to_ptr(&depth_stencil),
p_color_blend_state: option_to_ptr(&color_blend),
p_dynamic_state: option_to_ptr(&dynamic),
layout: desc.layout.pipeline_layout.handle(),
render_pass: desc.render_pass.unwrap_or(vk::RenderPass::null()),
subpass: desc.subpass.unwrap_or(0),
base_pipeline_handle: desc
.base_pipeline
.map(|piepline| piepline.pipeline.handle())
.unwrap_or(vk::Pipeline::null()),
..Default::default()
};
unsafe {
device.dev().create_graphics_pipelines(
vk::PipelineCache::null(),
core::slice::from_ref(info),
None,
)
}
}
};
let pipeline = match result {
Ok(pipelines) => pipelines[0],
Err((pipelines, error)) => {
tracing::error!("failed to create pipelines with :{error}");
for pipeline in pipelines {
unsafe {
device.dev().destroy_pipeline(pipeline, None);
}
}
return Err(error.into());
}
};
Ok(Self {
pipeline: DeviceOwnedDebugObject::new(device, pipeline, name)?,
})
}
}