atagen

monolith

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