pipeline cache
This commit is contained in:
parent
cf3244197e
commit
44ff4c4839
|
|
@ -52,6 +52,9 @@ petgraph = "0.7"
|
|||
itertools = "0.14.0"
|
||||
ahash = "0.8"
|
||||
|
||||
# for non-cryptographic hashing of resources like pipelines, e.g. for caching
|
||||
md-5 = "0.11.0"
|
||||
|
||||
parking_lot = "0.12.3"
|
||||
|
||||
tokio = "1.42"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ vk-mem = { workspace = true }
|
|||
gpu-allocator = { workspace = true }
|
||||
rectangle-pack = { workspace = true }
|
||||
|
||||
md-5 = { workspace = true }
|
||||
|
||||
raw-window-handle = { workspace = true }
|
||||
egui = { workspace = true , features = ["bytemuck"]}
|
||||
egui_winit_platform = { workspace = true }
|
||||
|
|
|
|||
|
|
@ -547,7 +547,7 @@ pub mod traits {
|
|||
self.device().dev().cmd_bind_pipeline(
|
||||
self.handle(),
|
||||
pipeline.bind_point(),
|
||||
pipeline.handle(),
|
||||
pipeline.raw(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use raw_window_handle::RawDisplayHandle;
|
|||
|
||||
use crate::{
|
||||
Instance, PhysicalDeviceFeatures, PhysicalDeviceInfo, Result,
|
||||
pipeline::pipeline_cache::PipelineCache,
|
||||
queue::{DeviceQueueInfos, DeviceQueues, Queue},
|
||||
sync::{self, BinarySemaphore, TimelineSemaphore},
|
||||
};
|
||||
|
|
@ -109,6 +110,9 @@ pub struct DeviceInner {
|
|||
pub(crate) device_extensions: DeviceExtensions,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) enabled_extensions: Vec<&'static CStr>,
|
||||
|
||||
pub(crate) pipeline_cache: PipelineCache,
|
||||
|
||||
_drop: DeviceDrop,
|
||||
}
|
||||
|
||||
|
|
@ -397,6 +401,7 @@ impl PhysicalDeviceInfo {
|
|||
raw: device.clone(),
|
||||
alloc2: Mutex::new(alloc2),
|
||||
instance: instance.clone(),
|
||||
pipeline_cache: PipelineCache::new(&device, &self)?,
|
||||
adapter: self,
|
||||
queues: device_queues,
|
||||
device_extensions,
|
||||
|
|
|
|||
|
|
@ -809,9 +809,9 @@ impl EguiState {
|
|||
"crates/renderer/shaders/egui_vert.spv",
|
||||
)?;
|
||||
|
||||
let pipeline = pipeline::Pipeline::new(
|
||||
let pipeline = pipeline::Pipeline::new_graphics(
|
||||
device.clone(),
|
||||
pipeline::PipelineDesc::Graphics(pipeline::GraphicsPipelineDesc {
|
||||
pipeline::GraphicsPipelineDesc {
|
||||
flags: Default::default(),
|
||||
name: Some("egui-pipeline".into()),
|
||||
shader_stages: &[
|
||||
|
|
@ -904,7 +904,7 @@ impl EguiState {
|
|||
dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
|
||||
..Default::default()
|
||||
}),
|
||||
}),
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok(Self {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use ash::{ext, prelude::*, vk};
|
|||
|
||||
use crate::{
|
||||
define_device_owned_handle,
|
||||
device::{Device, DeviceOwnedDebugObject},
|
||||
device::{Device, DeviceHandle, DeviceObject},
|
||||
make_extension,
|
||||
};
|
||||
|
||||
|
|
@ -40,12 +40,6 @@ pub struct PipelineLayoutDesc<'a> {
|
|||
pub name: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum PipelineDesc<'a> {
|
||||
Compute(ComputePipelineDesc<'a>),
|
||||
Graphics(GraphicsPipelineDesc<'a>),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ComputePipelineDesc<'a> {
|
||||
pub flags: vk::PipelineCreateFlags,
|
||||
|
|
@ -251,18 +245,17 @@ impl DescriptorPool {
|
|||
let info = &vk::DescriptorSetAllocateInfo::default()
|
||||
.descriptor_pool(self.handle())
|
||||
.set_layouts(&layouts);
|
||||
let sets = unsafe { self.device().dev().allocate_descriptor_sets(&info)? };
|
||||
let sets = unsafe { self.device().dev().allocate_descriptor_sets(info)? };
|
||||
|
||||
for (&set, desc) in sets.iter().zip(descs) {
|
||||
if let Some(name) = desc.name.as_ref() {
|
||||
unsafe { self.device().debug_name_object(set, &name) };
|
||||
unsafe { self.device().debug_name_object(set, name) };
|
||||
}
|
||||
}
|
||||
|
||||
Ok(sets)
|
||||
}
|
||||
|
||||
// pub fn free(&self) {}
|
||||
#[allow(dead_code)]
|
||||
pub fn reset(&self) -> VkResult<()> {
|
||||
unsafe {
|
||||
|
|
@ -474,18 +467,13 @@ impl ShaderModule {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub struct Pipeline {
|
||||
pipeline: DeviceOwnedDebugObject<vk::Pipeline>,
|
||||
pipeline: DeviceObject<vk::Pipeline>,
|
||||
bind_point: vk::PipelineBindPoint,
|
||||
}
|
||||
|
||||
impl Drop for Pipeline {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.pipeline
|
||||
.dev()
|
||||
.dev()
|
||||
.destroy_pipeline(self.pipeline.handle(), None);
|
||||
}
|
||||
impl DeviceHandle for vk::Pipeline {
|
||||
unsafe fn destroy(&mut self, device: &Device) {
|
||||
unsafe { device.raw.destroy_pipeline(*self, None) };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -500,224 +488,314 @@ impl ShaderStageDesc<'_> {
|
|||
}
|
||||
|
||||
impl Pipeline {
|
||||
pub fn new(device: Device, desc: PipelineDesc) -> VkResult<Self> {
|
||||
let name: Option<Cow<'static, str>>;
|
||||
let bind_point: vk::PipelineBindPoint;
|
||||
let result = match desc {
|
||||
PipelineDesc::Compute(desc) => {
|
||||
name = desc.name;
|
||||
bind_point = vk::PipelineBindPoint::COMPUTE;
|
||||
let info = &vk::ComputePipelineCreateInfo::default()
|
||||
.flags(desc.flags)
|
||||
.layout(desc.layout.handle())
|
||||
.base_pipeline_handle(
|
||||
desc.base_pipeline
|
||||
.map(|p| p.handle())
|
||||
.unwrap_or(vk::Pipeline::null()),
|
||||
)
|
||||
.stage(desc.shader_stage.as_create_info());
|
||||
pub fn new_compute(device: Device, desc: ComputePipelineDesc) -> crate::Result<Self> {
|
||||
let info = &vk::ComputePipelineCreateInfo::default()
|
||||
.flags(desc.flags)
|
||||
.layout(desc.layout.handle())
|
||||
.base_pipeline_handle(
|
||||
desc.base_pipeline
|
||||
.map(|p| p.raw())
|
||||
.unwrap_or(vk::Pipeline::null()),
|
||||
)
|
||||
.stage(desc.shader_stage.as_create_info());
|
||||
|
||||
unsafe {
|
||||
device.dev().create_compute_pipelines(
|
||||
vk::PipelineCache::null(),
|
||||
core::slice::from_ref(info),
|
||||
None,
|
||||
)
|
||||
}
|
||||
}
|
||||
PipelineDesc::Graphics(desc) => {
|
||||
name = desc.name;
|
||||
bind_point = vk::PipelineBindPoint::GRAPHICS;
|
||||
|
||||
let stages = desc
|
||||
.shader_stages
|
||||
.iter()
|
||||
.map(|stage| stage.as_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 info = vk::PipelineMultisampleStateCreateInfo::default()
|
||||
.flags(state.flags)
|
||||
.min_sample_shading(state.min_sample_shading)
|
||||
.rasterization_samples(state.rasterization_samples)
|
||||
.sample_mask(state.sample_mask)
|
||||
.sample_shading_enable(state.sample_shading_enable)
|
||||
.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 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 info = vk::PipelineDynamicStateCreateInfo::default()
|
||||
.flags(state.flags)
|
||||
.dynamic_states(state.dynamic_states);
|
||||
|
||||
info
|
||||
});
|
||||
|
||||
let mut rendering = desc.rendering.map(|state| {
|
||||
let info = vk::PipelineRenderingCreateInfo::default()
|
||||
.color_attachment_formats(state.color_formats)
|
||||
.depth_attachment_format(state.depth_format.unwrap_or_default())
|
||||
.stencil_attachment_format(state.stencil_format.unwrap_or_default());
|
||||
|
||||
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 mut 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.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()
|
||||
};
|
||||
|
||||
if let Some(rendering) = rendering.as_mut() {
|
||||
info = info.push_next(rendering)
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
let pipeline = unsafe {
|
||||
device
|
||||
.dev()
|
||||
.create_compute_pipelines(
|
||||
device.pipeline_cache.raw,
|
||||
core::slice::from_ref(info),
|
||||
None,
|
||||
)
|
||||
// It's cool to just take the first one and ignore any
|
||||
// potentially created pipelines since we know there wont be any
|
||||
// others.
|
||||
.map_err(|(_, err)| err)?[0]
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
pipeline: DeviceOwnedDebugObject::new(device, pipeline, name)?,
|
||||
bind_point,
|
||||
pipeline: DeviceObject::new(pipeline, device, desc.name),
|
||||
bind_point: vk::PipelineBindPoint::COMPUTE,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> vk::Pipeline {
|
||||
self.pipeline.handle()
|
||||
pub fn new_graphics(device: Device, desc: GraphicsPipelineDesc) -> crate::Result<Self> {
|
||||
let stages = desc
|
||||
.shader_stages
|
||||
.iter()
|
||||
.map(|stage| stage.as_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 info = vk::PipelineMultisampleStateCreateInfo::default()
|
||||
.flags(state.flags)
|
||||
.min_sample_shading(state.min_sample_shading)
|
||||
.rasterization_samples(state.rasterization_samples)
|
||||
.sample_mask(state.sample_mask)
|
||||
.sample_shading_enable(state.sample_shading_enable)
|
||||
.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 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 info = vk::PipelineDynamicStateCreateInfo::default()
|
||||
.flags(state.flags)
|
||||
.dynamic_states(state.dynamic_states);
|
||||
|
||||
info
|
||||
});
|
||||
|
||||
let mut rendering = desc.rendering.map(|state| {
|
||||
let info = vk::PipelineRenderingCreateInfo::default()
|
||||
.color_attachment_formats(state.color_formats)
|
||||
.depth_attachment_format(state.depth_format.unwrap_or_default())
|
||||
.stencil_attachment_format(state.stencil_format.unwrap_or_default());
|
||||
|
||||
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 mut 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.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)
|
||||
.unwrap_or(vk::Pipeline::null()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if let Some(rendering) = rendering.as_mut() {
|
||||
info = info.push_next(rendering)
|
||||
}
|
||||
|
||||
let pipeline = unsafe {
|
||||
device
|
||||
.dev()
|
||||
.create_graphics_pipelines(
|
||||
device.pipeline_cache.raw,
|
||||
core::slice::from_ref(&info),
|
||||
None,
|
||||
)
|
||||
// It's cool to just take the first one and ignore any
|
||||
// potentially created pipelines since we know there wont be any
|
||||
// others.
|
||||
.map_err(|(_, err)| err)?[0]
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
pipeline: DeviceObject::new(pipeline, device, desc.name),
|
||||
bind_point: vk::PipelineBindPoint::GRAPHICS,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> vk::Pipeline {
|
||||
*self.pipeline
|
||||
}
|
||||
pub fn bind_point(&self) -> vk::PipelineBindPoint {
|
||||
self.bind_point
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod pipeline_cache {
|
||||
use ash::vk;
|
||||
|
||||
use ash::Device;
|
||||
|
||||
use crate::PhysicalDeviceInfo;
|
||||
|
||||
pub struct PipelineCache {
|
||||
key: u128,
|
||||
pub(crate) raw: vk::PipelineCache,
|
||||
}
|
||||
|
||||
impl PipelineCache {
|
||||
const MAGIC: [u8; 4] = *b"VYPC";
|
||||
const KEY_VERSION: u32 = 1;
|
||||
const PATH: &'static str = "pipeline_cache.bin";
|
||||
fn calculate_key(adapter: &PhysicalDeviceInfo) -> u128 {
|
||||
use md5::Digest;
|
||||
let mut hasher = md5::Md5::new();
|
||||
let props = &adapter.properties;
|
||||
hasher.update(bytemuck::bytes_of(&[
|
||||
props.core.vendor_id,
|
||||
props.core.api_version,
|
||||
props.core.device_id,
|
||||
props.core.driver_version,
|
||||
]));
|
||||
u128::from_le_bytes(hasher.finalize().into())
|
||||
}
|
||||
|
||||
fn load_from_disk(key: u128) -> Option<(u128, Vec<u8>)> {
|
||||
use std::io::Read;
|
||||
|
||||
let file = std::fs::File::open(Self::PATH).ok()?;
|
||||
let mut reader = std::io::BufReader::new(file);
|
||||
let mut magic = [0; 4];
|
||||
reader.read_exact(&mut magic).ok()?;
|
||||
if magic != Self::MAGIC {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut version = 0;
|
||||
reader
|
||||
.read_exact(bytemuck::bytes_of_mut(&mut version))
|
||||
.ok()?;
|
||||
if version != Self::KEY_VERSION {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut disk_key = 0;
|
||||
reader
|
||||
.read_exact(bytemuck::bytes_of_mut(&mut disk_key))
|
||||
.ok()?;
|
||||
if disk_key != key {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut data = Vec::new();
|
||||
reader.read_to_end(&mut data).ok()?;
|
||||
|
||||
Some((key, data))
|
||||
}
|
||||
|
||||
fn write_to_disk(key: u128, data: &[u8]) -> std::io::Result<()> {
|
||||
use std::io::Write;
|
||||
|
||||
let file = std::fs::File::create(Self::PATH)?;
|
||||
let mut writer = std::io::BufWriter::new(file);
|
||||
writer.write_all(&Self::MAGIC)?;
|
||||
writer.write_all(bytemuck::bytes_of(&Self::KEY_VERSION))?;
|
||||
writer.write_all(bytemuck::bytes_of(&key))?;
|
||||
writer.write_all(data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn new(device: &Device, adapter: &PhysicalDeviceInfo) -> crate::Result<Self> {
|
||||
let key = Self::calculate_key(adapter);
|
||||
let data = Self::load_from_disk(key).map(|(key, data)| {
|
||||
tracing::info!("loaded pipeline cache from disk with key {key:x}");
|
||||
data
|
||||
});
|
||||
|
||||
let info = vk::PipelineCacheCreateInfo::default()
|
||||
.flags(vk::PipelineCacheCreateFlags::EXTERNALLY_SYNCHRONIZED)
|
||||
.initial_data(data.as_deref().unwrap_or_default());
|
||||
|
||||
let cache = unsafe { device.create_pipeline_cache(&info, None)? };
|
||||
|
||||
Ok(Self { key, raw: cache })
|
||||
}
|
||||
|
||||
pub fn export(&self, device: &ash::Device) -> crate::Result<Vec<u8>> {
|
||||
let data = unsafe { device.get_pipeline_cache_data(self.raw)? };
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -201,9 +201,9 @@ impl Wireframe {
|
|||
"crates/renderer/shaders/wireframe.spv",
|
||||
)?;
|
||||
|
||||
let pipeline = pipeline::Pipeline::new(
|
||||
let pipeline = pipeline::Pipeline::new_graphics(
|
||||
device.clone(),
|
||||
pipeline::PipelineDesc::Graphics(pipeline::GraphicsPipelineDesc {
|
||||
pipeline::GraphicsPipelineDesc {
|
||||
flags: Default::default(),
|
||||
name: Some("wireframe-pipeline".into()),
|
||||
shader_stages: &[
|
||||
|
|
@ -298,7 +298,7 @@ impl Wireframe {
|
|||
dynamic_states: &[vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR],
|
||||
..Default::default()
|
||||
}),
|
||||
}),
|
||||
},
|
||||
)?;
|
||||
|
||||
Ok((pipeline, pipeline_layout))
|
||||
|
|
|
|||
Loading…
Reference in a new issue