atagen

monolith

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