atagen

monolith

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