1use {
2 bytemuck::cast_slice,
3 glam::{Mat4, vec3},
4 vk_graph::{
5 Graph,
6 cmd::{LoadOp, StoreOp},
7 driver::{
8 DriverError,
9 compute::{ComputePipeline, ComputePipelineInfo},
10 device::Device,
11 graphics::{GraphicsPipeline, GraphicsPipelineInfo},
12 shader::Shader,
13 sync::AccessType,
14 },
15 node::{AnyImageNode, SwapchainImageNode},
16 },
17 vk_shader_macros::include_glsl,
18};
19
20pub struct ComputePresenter([ComputePipeline; 2]);
22
23impl ComputePresenter {
24 pub fn new(device: &Device) -> Result<Self, DriverError> {
26 let pipeline1 = ComputePipeline::create(
27 device,
28 ComputePipelineInfo::default(),
29 Shader::new_compute(include_glsl!("res/shader/compute/present1.comp").as_slice()),
30 )?;
31 let pipeline2 = ComputePipeline::create(
32 device,
33 ComputePipelineInfo::default(),
34 Shader::new_compute(include_glsl!("res/shader/compute/present2.comp").as_slice()),
35 )?;
36
37 Ok(Self([pipeline1, pipeline2]))
38 }
39
40 pub fn present_image(
42 &self,
43 graph: &mut Graph,
44 image: impl Into<AnyImageNode>,
45 swapchain: SwapchainImageNode,
46 ) {
47 let image = image.into();
48 let swapchain_info = graph.resource(swapchain).info;
50
51 graph
54 .begin_cmd()
55 .debug_name("present (from compute)")
56 .bind_pipeline(&self.0[0])
57 .shader_resource_access(0, image, AccessType::ComputeShaderReadOther)
58 .shader_resource_access(1, swapchain, AccessType::ComputeShaderWrite)
59 .record_cmd(move |cmd| {
60 cmd.dispatch(swapchain_info.width, swapchain_info.height, 1);
61 });
62 }
63
64 pub fn present_images(
66 &self,
67 graph: &mut Graph,
68 top_image: impl Into<AnyImageNode>,
69 bottom_image: impl Into<AnyImageNode>,
70 swapchain: SwapchainImageNode,
71 ) {
72 let top_image = top_image.into();
73 let bottom_image = bottom_image.into();
74 let swapchain_info = graph.resource(swapchain).info;
77
78 graph
81 .begin_cmd()
82 .debug_name("present (from compute)")
83 .bind_pipeline(&self.0[1])
84 .shader_resource_access((0, [0]), top_image, AccessType::ComputeShaderReadOther)
85 .shader_resource_access((0, [1]), bottom_image, AccessType::ComputeShaderReadOther)
86 .shader_resource_access(1, swapchain, AccessType::ComputeShaderWrite)
87 .record_cmd(move |cmd| {
88 cmd.dispatch(swapchain_info.width, swapchain_info.height, 1);
89 });
90 }
91}
92
93pub struct GraphicPresenter {
95 pipeline: GraphicsPipeline,
96}
97
98impl GraphicPresenter {
99 pub fn new(device: &Device) -> Result<Self, DriverError> {
101 let pipeline = GraphicsPipeline::create(
102 device,
103 GraphicsPipelineInfo::default(),
104 [
105 Shader::new_vertex(include_glsl!("res/shader/graphics/present.vert").as_slice()),
106 Shader::new_fragment(include_glsl!("res/shader/graphics/present.frag").as_slice()),
107 ],
108 )?;
109
110 Ok(Self { pipeline })
111 }
112
113 pub fn present_image(
115 &self,
116 graph: &mut Graph,
117 image: impl Into<AnyImageNode>,
118 swapchain: SwapchainImageNode,
119 ) {
120 let image = image.into();
121 let image_info = graph.resource(image).info;
122 let swapchain_info = graph.resource(swapchain).info;
123
124 let (image_width, image_height) = (image_info.width as f32, image_info.height as f32);
125 let (swapchain_width, swapchain_height) =
126 (swapchain_info.width as f32, swapchain_info.height as f32);
127
128 let scale = (swapchain_width / image_width).max(swapchain_height / image_height);
129 let transform = Mat4::from_scale(vec3(
130 scale * image_width / swapchain_width,
131 scale * image_height / swapchain_height,
132 1.0,
133 ));
134
135 graph
136 .begin_cmd()
137 .debug_name("present (from graphics)")
138 .bind_pipeline(&self.pipeline)
139 .shader_resource_access(
140 0,
141 image,
142 AccessType::FragmentShaderReadSampledImageOrUniformTexelBuffer,
143 )
144 .color_attachment_image(0, swapchain, LoadOp::DontCare, StoreOp::Store)
145 .record_cmd(move |cmd| {
146 cmd.push_constants(0, cast_slice(&transform.to_cols_array()))
148 .draw(6, 1, 0, 0);
149 });
150 }
151}