824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 1 | use crate::Error; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 2 | use crate::device::Shared; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 3 | use ash::vk; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 4 | use std::collections::HashMap; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 5 | use std::sync::Arc; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 6 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 7 | /// Push constants shared by every shader, see `shaders/push.glsl`. |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 8 | /// `dst` is the quad in normalized device coordinates as (x, y, w, h), |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 9 | /// `uv` the texture coordinate at each corner (TL, TR, BL, BR). |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 10 | #[repr(C)] |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 11 | #[derive(Clone, Copy, Debug, Default)] |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 12 | pub(crate) struct Push { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 13 | pub color: [f32; 4], |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 14 | pub dst: [f32; 4], |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 15 | pub uv: [[f32; 2]; 4], |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 16 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 17 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 18 | impl Push { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 19 | pub fn bytes(&self) -> &[u8] { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 20 | unsafe { std::slice::from_raw_parts((self as *const Self).cast::<u8>(), size_of::<Self>()) } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 21 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 22 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 23 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 24 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 25 | pub(crate) enum Kind { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 26 | Solid, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 27 | Texture, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 28 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 29 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 30 | pub(crate) struct Pipelines { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 31 | shared: Arc<Shared>, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 32 | pub set_layout: vk::DescriptorSetLayout, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 33 | pub layout: vk::PipelineLayout, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 34 | vert: vk::ShaderModule, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 35 | solid: vk::ShaderModule, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 36 | texture: vk::ShaderModule, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 37 | cache: HashMap<(vk::Format, Kind), vk::Pipeline>, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 38 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 39 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 40 | const QUAD_VERT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/quad.vert.spv")); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 41 | const SOLID_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/solid.frag.spv")); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 42 | const TEXTURE_FRAG: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/texture.frag.spv")); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 43 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 44 | impl Pipelines { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 45 | pub fn new(shared: &Arc<Shared>) -> Result<Self, Error> { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 46 | let d = &shared.device.device; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 47 | let bindings = [vk::DescriptorSetLayoutBinding::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 48 | .binding(0) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 49 | .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 50 | .descriptor_count(1) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 51 | .stage_flags(vk::ShaderStageFlags::FRAGMENT)]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 52 | let set_layout = unsafe { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 53 | d.create_descriptor_set_layout( |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 54 | &vk::DescriptorSetLayoutCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 55 | .flags(vk::DescriptorSetLayoutCreateFlags::PUSH_DESCRIPTOR_KHR) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 56 | .bindings(&bindings), |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 57 | None, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 58 | )? |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 59 | }; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 60 | let ranges = [vk::PushConstantRange::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 61 | .stage_flags(vk::ShaderStageFlags::VERTEX | vk::ShaderStageFlags::FRAGMENT) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 62 | .size(size_of::<Push>() as u32)]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 63 | let set_layouts = [set_layout]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 64 | let layout = unsafe { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 65 | d.create_pipeline_layout( |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 66 | &vk::PipelineLayoutCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 67 | .set_layouts(&set_layouts) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 68 | .push_constant_ranges(&ranges), |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 69 | None, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 70 | )? |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 71 | }; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 72 | let module = |code: &[u8]| -> Result<vk::ShaderModule, Error> { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 73 | let words = ash::util::read_spv(&mut std::io::Cursor::new(code)) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 74 | .map_err(|_| vk::Result::ERROR_INVALID_SHADER_NV)?; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 75 | Ok(unsafe { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 76 | d.create_shader_module(&vk::ShaderModuleCreateInfo::default().code(&words), None)? |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 77 | }) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 78 | }; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 79 | Ok(Self { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 80 | shared: shared.clone(), |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 81 | set_layout, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 82 | layout, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 83 | vert: module(QUAD_VERT)?, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 84 | solid: module(SOLID_FRAG)?, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 85 | texture: module(TEXTURE_FRAG)?, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 86 | cache: HashMap::new(), |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 87 | }) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 88 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 89 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 90 | pub fn get(&mut self, format: vk::Format, kind: Kind) -> Result<vk::Pipeline, Error> { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 91 | if let Some(&p) = self.cache.get(&(format, kind)) { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 92 | return Ok(p); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 93 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 94 | let d = &self.shared.device.device; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 95 | let frag = match kind { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 96 | Kind::Solid => self.solid, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 97 | Kind::Texture => self.texture, |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 98 | }; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 99 | let stages = [ |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 100 | vk::PipelineShaderStageCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 101 | .stage(vk::ShaderStageFlags::VERTEX) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 102 | .module(self.vert) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 103 | .name(c"main"), |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 104 | vk::PipelineShaderStageCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 105 | .stage(vk::ShaderStageFlags::FRAGMENT) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 106 | .module(frag) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 107 | .name(c"main"), |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 108 | ]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 109 | let vertex = vk::PipelineVertexInputStateCreateInfo::default(); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 110 | let assembly = vk::PipelineInputAssemblyStateCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 111 | .topology(vk::PrimitiveTopology::TRIANGLE_STRIP); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 112 | let viewport = vk::PipelineViewportStateCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 113 | .viewport_count(1) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 114 | .scissor_count(1); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 115 | let raster = vk::PipelineRasterizationStateCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 116 | .polygon_mode(vk::PolygonMode::FILL) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 117 | .cull_mode(vk::CullModeFlags::NONE) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 118 | .line_width(1.0); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 119 | let multisample = vk::PipelineMultisampleStateCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 120 | .rasterization_samples(vk::SampleCountFlags::TYPE_1); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 121 | let attachments = [vk::PipelineColorBlendAttachmentState::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 122 | .blend_enable(true) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 123 | .src_color_blend_factor(vk::BlendFactor::ONE) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 124 | .dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 125 | .color_blend_op(vk::BlendOp::ADD) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 126 | .src_alpha_blend_factor(vk::BlendFactor::ONE) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 127 | .dst_alpha_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 128 | .alpha_blend_op(vk::BlendOp::ADD) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 129 | .color_write_mask(vk::ColorComponentFlags::RGBA)]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 130 | let blend = vk::PipelineColorBlendStateCreateInfo::default().attachments(&attachments); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 131 | let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 132 | let dynamic = vk::PipelineDynamicStateCreateInfo::default().dynamic_states(&dynamic_states); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 133 | let formats = [format]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 134 | let mut rendering = |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 135 | vk::PipelineRenderingCreateInfo::default().color_attachment_formats(&formats); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 136 | let info = vk::GraphicsPipelineCreateInfo::default() |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 137 | .stages(&stages) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 138 | .vertex_input_state(&vertex) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 139 | .input_assembly_state(&assembly) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 140 | .viewport_state(&viewport) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 141 | .rasterization_state(&raster) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 142 | .multisample_state(&multisample) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 143 | .color_blend_state(&blend) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 144 | .dynamic_state(&dynamic) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 145 | .layout(self.layout) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 146 | .push_next(&mut rendering); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 147 | let pipeline = |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 148 | unsafe { d.create_graphics_pipelines(vk::PipelineCache::null(), &[info], None) } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 149 | .map_err(|(_, e)| e)?[0]; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 150 | self.cache.insert((format, kind), pipeline); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 151 | Ok(pipeline) |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 152 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 153 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 154 | |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 155 | impl Drop for Pipelines { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 156 | fn drop(&mut self) { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 157 | let d = &self.shared.device.device; |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 158 | unsafe { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 159 | for (_, p) in self.cache.drain() { |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 160 | d.destroy_pipeline(p, None); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 161 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 162 | d.destroy_shader_module(self.vert, None); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 163 | d.destroy_shader_module(self.solid, None); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 164 | d.destroy_shader_module(self.texture, None); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 165 | d.destroy_pipeline_layout(self.layout, None); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 166 | d.destroy_descriptor_set_layout(self.set_layout, None); |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 167 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 168 | } |
824bf02b6e55 | atagen | 2026-10-16 09:15 UTC | 169 | } |