atagen

monolith

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