atagen

monolith

public
Star0
Watch0
e3e5f00d41e2ee42f62667b3766fd6c9cf79f0e1
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/render-vk/src/frame.rsRust266 lines7.3 KB
1
use crate::Error;
2
use crate::image::{VulkanTarget, VulkanTexture};
3
use crate::pipeline::{Kind, Push};
4
use crate::renderer::VulkanRenderer;
5
use crate::transform::{rect_to_framebuffer, texture_uvs, to_framebuffer};
6
use ash::vk;
7
use smithay::backend::renderer::sync::SyncPoint;
8
use smithay::backend::renderer::{Color32F, ContextId, Frame, Texture};
9
use smithay::utils::{Buffer, Physical, Rectangle, Size, Transform};
10
use std::sync::Arc;
11
12
pub(crate) enum Op {
13
    Clear {
14
        color: [f32; 4],
15
        rects: Vec<vk::Rect2D>,
16
    },
17
    Draw {
18
        kind: Kind,
19
        texture: Option<VulkanTexture>,
20
        push: Push,
21
        scissors: Vec<vk::Rect2D>,
22
    },
23
}
24
25
/// A frame in progress. Draws are recorded and submitted together by [`Frame::finish`].
26
pub struct VulkanFrame<'frame, 'buffer> {
27
    renderer: &'frame mut VulkanRenderer,
28
    target: &'frame mut VulkanTarget<'buffer>,
29
    output: Size<i32, Physical>,
30
    transform: Transform,
31
    ops: Vec<Op>,
32
}
33
34
impl std::fmt::Debug for VulkanFrame<'_, '_> {
35
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36
        f.debug_struct("VulkanFrame")
37
            .field("output", &self.output)
38
            .field("ops", &self.ops.len())
39
            .finish()
40
    }
41
}
42
43
impl<'frame, 'buffer> VulkanFrame<'frame, 'buffer> {
44
    pub(crate) fn new(
45
        renderer: &'frame mut VulkanRenderer,
46
        target: &'frame mut VulkanTarget<'buffer>,
47
        output: Size<i32, Physical>,
48
        transform: Transform,
49
    ) -> Self {
50
        Self {
51
            renderer,
52
            target,
53
            output,
54
            transform,
55
            ops: Vec::new(),
56
        }
57
    }
58
59
    fn fb_size(&self) -> Size<i32, Physical> {
60
        (self.target.width() as i32, self.target.height() as i32).into()
61
    }
62
63
    fn fb_rect(&self, r: Rectangle<i32, Physical>) -> Option<vk::Rect2D> {
64
        let r = rect_to_framebuffer(r, self.output, self.transform)
65
            .intersection(Rectangle::from_size(self.fb_size()))?;
66
        Some(vk::Rect2D {
67
            offset: vk::Offset2D {
68
                x: r.loc.x,
69
                y: r.loc.y,
70
            },
71
            extent: vk::Extent2D {
72
                width: r.size.w as u32,
73
                height: r.size.h as u32,
74
            },
75
        })
76
    }
77
78
    fn scissors(
79
        &self,
80
        dst: Rectangle<i32, Physical>,
81
        damage: &[Rectangle<i32, Physical>],
82
    ) -> Vec<vk::Rect2D> {
83
        damage
84
            .iter()
85
            .filter_map(|d| d.intersection(Rectangle::from_size(dst.size)))
86
            .filter_map(|mut d| {
87
                d.loc += dst.loc;
88
                self.fb_rect(d)
89
            })
90
            .collect()
91
    }
92
93
    /// Draws a texture through the transition hook in `shaders/effect.frag`.
94
    #[expect(clippy::too_many_arguments)]
95
    pub fn render_effect(
96
        &mut self,
97
        texture: &VulkanTexture,
98
        src: Rectangle<f64, Buffer>,
99
        dst: Rectangle<i32, Physical>,
100
        damage: &[Rectangle<i32, Physical>],
101
        src_transform: Transform,
102
        alpha: f32,
103
        effect: Effect,
104
    ) -> Result<(), Error> {
105
        let params = [effect.progress, effect.kind as u32 as f32, 0.0, 0.0];
106
        self.draw_texture(
107
            texture,
108
            src,
109
            dst,
110
            damage,
111
            src_transform,
112
            alpha,
113
            Kind::Effect,
114
            params,
115
        )
116
    }
117
118
    #[expect(clippy::too_many_arguments)]
119
    fn draw_texture(
120
        &mut self,
121
        texture: &VulkanTexture,
122
        src: Rectangle<f64, Buffer>,
123
        dst: Rectangle<i32, Physical>,
124
        damage: &[Rectangle<i32, Physical>],
125
        src_transform: Transform,
126
        alpha: f32,
127
        kind: Kind,
128
        effect: [f32; 4],
129
    ) -> Result<(), Error> {
130
        if !Arc::ptr_eq(&texture.0.shared, self.renderer.shared()) {
131
            return Err(Error::ForeignTexture);
132
        }
133
        if dst.size.w <= 0 || dst.size.h <= 0 || Arc::ptr_eq(&texture.0, &self.target.0) {
134
            return Ok(());
135
        }
136
        let scissors = self.scissors(dst, damage);
137
        if scissors.is_empty() {
138
            return Ok(());
139
        }
140
        let uvs = texture_uvs(src, dst.size, texture.size(), src_transform);
141
        let (fb, uv) = to_framebuffer(dst, uvs, self.output, self.transform);
142
        let push = Push {
143
            dst: self.ndc(fb),
144
            uv,
145
            color: [1.0, 1.0, 1.0, alpha],
146
            effect,
147
        };
148
        self.ops.push(Op::Draw {
149
            kind,
150
            texture: Some(texture.clone()),
151
            push,
152
            scissors,
153
        });
154
        Ok(())
155
    }
156
157
    fn ndc(&self, r: Rectangle<i32, Physical>) -> [f32; 4] {
158
        let fb = self.fb_size();
159
        let (w, h) = (fb.w as f32, fb.h as f32);
160
        [
161
            r.loc.x as f32 / w * 2.0 - 1.0,
162
            r.loc.y as f32 / h * 2.0 - 1.0,
163
            r.size.w as f32 / w * 2.0,
164
            r.size.h as f32 / h * 2.0,
165
        ]
166
    }
167
}
168
169
impl Frame for VulkanFrame<'_, '_> {
170
    type Error = Error;
171
    type TextureId = VulkanTexture;
172
173
    fn context_id(&self) -> ContextId<VulkanTexture> {
174
        self.renderer.context_id_ref().clone()
175
    }
176
177
    fn clear(&mut self, color: Color32F, at: &[Rectangle<i32, Physical>]) -> Result<(), Error> {
178
        let rects: Vec<_> = at.iter().filter_map(|r| self.fb_rect(*r)).collect();
179
        if !rects.is_empty() {
180
            self.ops.push(Op::Clear {
181
                color: color.components(),
182
                rects,
183
            });
184
        }
185
        Ok(())
186
    }
187
188
    fn draw_solid(
189
        &mut self,
190
        dst: Rectangle<i32, Physical>,
191
        damage: &[Rectangle<i32, Physical>],
192
        color: Color32F,
193
    ) -> Result<(), Error> {
194
        let scissors = self.scissors(dst, damage);
195
        if scissors.is_empty() {
196
            return Ok(());
197
        }
198
        let (fb, _) = to_framebuffer(dst, [[0.0; 2]; 4], self.output, self.transform);
199
        let push = Push {
200
            dst: self.ndc(fb),
201
            uv: [[0.0; 2]; 4],
202
            color: color.components(),
203
            effect: [0.0; 4],
204
        };
205
        self.ops.push(Op::Draw {
206
            kind: Kind::Solid,
207
            texture: None,
208
            push,
209
            scissors,
210
        });
211
        Ok(())
212
    }
213
214
    fn render_texture_from_to(
215
        &mut self,
216
        texture: &VulkanTexture,
217
        src: Rectangle<f64, Buffer>,
218
        dst: Rectangle<i32, Physical>,
219
        damage: &[Rectangle<i32, Physical>],
220
        _opaque_regions: &[Rectangle<i32, Physical>],
221
        src_transform: Transform,
222
        alpha: f32,
223
    ) -> Result<(), Error> {
224
        self.draw_texture(
225
            texture,
226
            src,
227
            dst,
228
            damage,
229
            src_transform,
230
            alpha,
231
            Kind::Texture,
232
            [0.0; 4],
233
        )
234
    }
235
236
    fn transformation(&self) -> Transform {
237
        self.transform
238
    }
239
240
    fn output_size(&self) -> Size<i32, Physical> {
241
        self.output
242
    }
243
244
    fn wait(&mut self, sync: &SyncPoint) -> Result<(), Error> {
245
        sync.wait().map_err(|_| Error::Interrupted)
246
    }
247
248
    fn finish(mut self) -> Result<SyncPoint, Error> {
249
        let ops = std::mem::take(&mut self.ops);
250
        self.renderer.submit(self.target, ops)
251
    }
252
}
253
254
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
255
pub enum Transition {
256
    Move = 0,
257
    Spawn = 1,
258
    Close = 2,
259
}
260
261
/// A window transition for the effect shader, with `progress` in [0, 1].
262
#[derive(Clone, Copy, Debug, PartialEq)]
263
pub struct Effect {
264
    pub kind: Transition,
265
    pub progress: f32,
266
}