narui_core/vulkano_render/
render.rs

1use super::{glyph_brush::GlyphBrush, input_handler::InputHandler, lyon::Lyon};
2use crate::{
3    eval::{
4        delta_eval::Evaluator,
5        layout::{Layouter, PositionedElement},
6    },
7    geom::Rect,
8    util::fps_report::FPSReporter,
9    RenderObject,
10    UnevaluatedFragment,
11};
12use freelist::Idx;
13
14use crate::{
15    context::context,
16    eval::layout::RenderObjectOrSubPass,
17    vulkano_render::{
18        primitive_renderer::Renderer,
19        subpass_stack::{create_framebuffer, AbstractFramebuffer, AbstractImage, SubPassStack},
20        vk_util::VulkanContext,
21    },
22};
23use std::{
24    sync::Arc,
25    time::{Duration, Instant},
26};
27use vulkano::{
28    format::Format,
29    image::{ImageAccess, ImageUsage, SwapchainImage},
30    render_pass::RenderPass,
31    swapchain,
32    swapchain::{AcquireError, PresentMode, Swapchain, SwapchainCreationError},
33    sync,
34    sync::{FlushError, GpuFuture},
35};
36use vulkano_win::VkSurfaceBuild;
37use winit::{
38    event::{Event, WindowEvent},
39    event_loop::{ControlFlow, EventLoop},
40    platform::run_return::EventLoopExtRunReturn,
41    window::{Window, WindowBuilder},
42};
43
44pub fn render(window_builder: WindowBuilder, top_node: UnevaluatedFragment) {
45    let mut event_loop: EventLoop<()> = EventLoop::new();
46    let VulkanContext { device, queues } = VulkanContext::create().unwrap();
47    let surface = window_builder.build_vk_surface(&event_loop, device.instance().clone()).unwrap();
48    let queue = queues
49        .iter()
50        .find(|&q| {
51            q.family().supports_graphics() && surface.is_supported(q.family()).unwrap_or(false)
52        })
53        .unwrap()
54        .clone();
55
56    let mut dimensions;
57
58    let caps = surface.capabilities(device.physical_device()).unwrap();
59    let format = Format::B8G8R8A8_SRGB;
60    let (mut swapchain, images) = {
61        let alpha = caps.supported_composite_alpha.iter().next().unwrap();
62        dimensions = surface.window().inner_size().into();
63        Swapchain::start(device.clone(), surface.clone())
64            .usage(ImageUsage {
65                color_attachment: true,
66                transfer_destination: true,
67                ..ImageUsage::none()
68            })
69            .num_images(caps.min_image_count)
70            .composite_alpha(alpha)
71            .dimensions(dimensions)
72            .present_mode(
73                if std::env::var("NARUI_PRESENT_MODE_MAILBOX").is_ok() {
74                    PresentMode::Mailbox
75                } else {
76                    PresentMode::Fifo
77                },
78            )
79            .format(format)
80            .build()
81            .expect("cant create swapchain")
82    };
83
84    let render_pass = vulkano::single_pass_renderpass!(device.clone(),
85        attachments: {
86            intermediary: {
87                load: Load,
88                store: Store,
89                format: swapchain.format(),
90                samples: 4,
91            },
92            depth: {
93                load: Load,
94                store: Store,
95                format: Format::D16_UNORM,
96                samples: 4,
97            },
98            color: {
99                load: DontCare,
100                store: Store,
101                format: swapchain.format(),
102                samples: 1,
103            }
104        },
105        pass: {
106            color: [intermediary],
107            depth_stencil: {depth},
108            resolve: [color],
109        }
110    )
111    .unwrap();
112
113    let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone());
114    let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
115
116
117    let mut fps_report = FPSReporter::new("gui");
118
119    let mut lyon_renderer = Lyon::new();
120    let mut text_render = GlyphBrush::new(queue.clone());
121    let mut renderer = Renderer::new(render_pass.clone(), device.clone(), queue.clone());
122    let mut input_handler = InputHandler::new();
123
124    let mut layouter = Layouter::new();
125    let mut evaluator = Evaluator::new(
126        context::VulkanContext { device: device.clone(), queues, render_pass: render_pass.clone() },
127        top_node,
128        &mut layouter,
129    );
130
131    let mut recreate_swapchain = false;
132    let mut has_update = true;
133    let mut input_render_objects: Vec<(Idx, Option<Rect>)> = Vec::new();
134
135    event_loop.run_return(move |event, _, control_flow| {
136        *control_flow = ControlFlow::WaitUntil(Instant::now() + Duration::from_millis(1000 / 70));
137        match event {
138            Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => {
139                *control_flow = ControlFlow::Exit;
140            }
141            Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
142                recreate_swapchain = true;
143                surface.window().request_redraw();
144            }
145            Event::WindowEvent { event, .. } => {
146                input_handler.enqueue_input(event);
147                *control_flow = ControlFlow::Poll;
148                return;
149            }
150            Event::MainEventsCleared => {
151                input_handler.handle_input(
152                    &input_render_objects[..],
153                    &layouter,
154                    evaluator.callback_context(&layouter),
155                );
156                has_update |= evaluator.update(&mut layouter);
157                if has_update {
158                    surface.window().request_redraw();
159                }
160            }
161            Event::RedrawRequested(_) => {
162                previous_frame_end.as_mut().unwrap().cleanup_finished();
163
164                if recreate_swapchain {
165                    dimensions = surface.window().inner_size().into();
166                    let (new_swapchain, new_images) =
167                        match swapchain.recreate().dimensions(dimensions).build() {
168                            Ok(r) => r,
169                            Err(SwapchainCreationError::UnsupportedDimensions) => {
170                                return;
171                            }
172                            Err(e) => panic!("Failed to recreate swapchain: {:?}", e),
173                        };
174
175                    swapchain = new_swapchain;
176                    framebuffers = window_size_dependent_setup(&new_images, render_pass.clone());
177                    recreate_swapchain = false;
178                }
179
180                let (image_num, acquire_fut) = match swapchain::acquire_next_image(
181                    swapchain.clone(),
182                    Some(Duration::from_millis(0)),
183                ) {
184                    Ok((image_num, suboptimal, acquire_future)) => {
185                        if suboptimal {
186                            println!("swapchain suboptimal, need to recreate it");
187                            recreate_swapchain = true;
188                        }
189                        (image_num, acquire_future)
190                    }
191                    Err(AcquireError::OutOfDate) => {
192                        println!("swapchain suboptimal, need to recreate it");
193                        recreate_swapchain = true;
194                        return;
195                    }
196                    Err(e) => panic!("Failed to acquire next image: {:?}", e),
197                };
198
199                has_update = false;
200
201                let (framebuffer, intermediary_image, depth_image): &(
202                    AbstractFramebuffer,
203                    AbstractImage,
204                    AbstractImage,
205                ) = &framebuffers[image_num];
206
207                input_render_objects.clear();
208
209                layouter.do_layout(evaluator.top_node, dimensions.into());
210
211                let mut subpass_stack = SubPassStack::new(
212                    format,
213                    queue.clone(),
214                    render_pass.clone(),
215                    framebuffer.clone(),
216                    intermediary_image.clone(),
217                    depth_image.clone(),
218                );
219
220                for (_, obj) in layouter.iter_layouted(evaluator.top_node) {
221                    text_render.prerender(&obj);
222                }
223                let (mut text_state, texture, texture_fut) = text_render.finish(&mut renderer.data);
224
225                for (idx, obj) in layouter.iter_layouted(evaluator.top_node) {
226                    subpass_stack.handle(&renderer.data, &obj);
227                    lyon_renderer.render(&mut renderer.data, &obj);
228                    text_render.render(&obj, &mut renderer.data, &mut text_state);
229                    renderer.render(&obj);
230                    if let PositionedElement {
231                        element: RenderObjectOrSubPass::RenderObject(RenderObject::Input { .. }),
232                        ..
233                    } = &obj
234                    {
235                        input_render_objects.push((idx, obj.clipping_rect));
236                    }
237                }
238                subpass_stack.finish(&renderer.data);
239                let (
240                    vertex_fut,
241                    primitive_fut,
242                    index_fut,
243                    descriptor_set,
244                    vertex_buffer,
245                    index_buffer,
246                ) = renderer.finish(texture);
247
248                let after_frame_callbacks = std::mem::take(&mut evaluator.after_frame_callbacks);
249                let callback_context = evaluator.callback_context(&layouter);
250                let command_buffer = subpass_stack.render(
251                    &callback_context,
252                    |builder, viewport, dimensions, offset, start, end| {
253                        renderer.render_part(
254                            builder,
255                            descriptor_set.clone(),
256                            viewport,
257                            dimensions,
258                            offset,
259                            start,
260                            end,
261                        )
262                    },
263                    vertex_buffer,
264                    index_buffer,
265                );
266                fps_report.frame();
267
268                let future = previous_frame_end
269                    .take()
270                    .unwrap()
271                    .join(
272                        texture_fut
273                            .map(|v| Box::new(v) as Box<dyn GpuFuture>)
274                            .unwrap_or_else(|| Box::new(sync::now(device.clone())) as _),
275                    )
276                    .join(index_fut)
277                    .join(vertex_fut)
278                    .join(primitive_fut)
279                    .join(acquire_fut)
280                    .then_execute(queue.clone(), command_buffer)
281                    .unwrap()
282                    .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
283                    .then_signal_fence_and_flush();
284
285                match future {
286                    Ok(future) => {
287                        previous_frame_end = Some(future.boxed());
288                    }
289                    Err(FlushError::OutOfDate) => {
290                        recreate_swapchain = true;
291                        previous_frame_end = Some(sync::now(device.clone()).boxed());
292                    }
293                    Err(e) => {
294                        println!("Failed to flush future: {:?}", e);
295                        previous_frame_end = Some(sync::now(device.clone()).boxed());
296                    }
297                }
298
299                for callback in after_frame_callbacks {
300                    callback(&callback_context);
301                }
302            }
303            _e => {}
304        }
305    });
306}
307
308/// This method is called once during initialization, then again whenever the
309/// window is resized
310fn window_size_dependent_setup(
311    images: &[Arc<SwapchainImage<Window>>],
312    render_pass: Arc<RenderPass>,
313) -> Vec<(AbstractFramebuffer, AbstractImage, AbstractImage)> {
314    let dimensions = images[0].dimensions();
315    images
316        .iter()
317        .map(|image| {
318            let fb = create_framebuffer(
319                [dimensions.width(), dimensions.height()],
320                render_pass.clone(),
321                image.format(),
322                Some(image.clone()),
323            );
324            (fb.0, fb.3, fb.4)
325        })
326        .collect::<Vec<_>>()
327}