comfy_wgpu/egui_integration.rs
1use egui::ClippedPrimitive;
2
3pub struct EguiRenderRoutine {
4 pub render_pass: egui_wgpu::Renderer,
5 pub screen_descriptor: egui_wgpu::ScreenDescriptor,
6 #[allow(dead_code)]
7 textures_to_free: Vec<egui::TextureId>,
8}
9
10impl EguiRenderRoutine {
11 /// Creates a new render routine to render a egui UI.
12 ///
13 /// Egui will always output gamma-encoded color. It will determine if to do
14 /// this in the shader manually based on the output format.
15 pub fn new(
16 device: &wgpu::Device,
17 surface_format: wgpu::TextureFormat,
18 samples: u32,
19 width: u32,
20 height: u32,
21 scale_factor: f32,
22 ) -> Self {
23 let render_pass =
24 egui_wgpu::Renderer::new(device, surface_format, None, samples);
25
26 Self {
27 render_pass,
28 screen_descriptor: egui_wgpu::ScreenDescriptor {
29 size_in_pixels: [width, height],
30 pixels_per_point: scale_factor,
31 },
32 textures_to_free: Vec::new(),
33 }
34 }
35
36 pub fn resize(
37 &mut self,
38 new_width: u32,
39 new_height: u32,
40 new_scale_factor: f32,
41 ) {
42 self.screen_descriptor = egui_wgpu::ScreenDescriptor {
43 size_in_pixels: [new_width, new_height],
44 pixels_per_point: new_scale_factor,
45 };
46 }
47
48 pub fn end_frame_and_render(
49 &mut self,
50 ctx: &egui::Context,
51 device: &wgpu::Device,
52 queue: &wgpu::Queue,
53 encoder: &mut wgpu::CommandEncoder,
54 pixels_per_point: f32,
55 // view: &wgpu::TextureView,
56 // render_pass: &'a mut wgpu::RenderPass<'a>,
57 ) -> Vec<ClippedPrimitive> {
58 let egui::FullOutput { shapes, textures_delta, .. } = ctx.end_frame();
59
60 let paint_jobs = ctx.tessellate(shapes, pixels_per_point);
61
62 for id in textures_delta.free {
63 self.render_pass.free_texture(&id);
64 }
65
66 for (id, image_delta) in textures_delta.set {
67 self.render_pass.update_texture(device, queue, id, &image_delta);
68 }
69
70 self.render_pass.update_buffers(
71 device,
72 queue,
73 encoder,
74 &paint_jobs,
75 &self.screen_descriptor,
76 );
77
78 paint_jobs
79 // self.render_pass.execute(
80 // encoder,
81 // view,
82 // &paint_jobs,
83 // &self.screen_descriptor,
84 // None,
85 // );
86 }
87
88 // pub fn add_to_graph<'node>(
89 // &'node mut self,
90 // graph: &mut RenderGraph<'node>,
91 // mut input: Input<'node>,
92 // output: RenderTargetHandle,
93 // ) {
94 // let mut builder = graph.add_node("egui");
95 //
96 // let output_handle = builder.add_render_target_output(output);
97 //
98 // let rpass_handle = builder.add_renderpass(RenderPassTargets {
99 // targets: vec![RenderPassTarget {
100 // color: output_handle,
101 // clear: Color::BLACK,
102 // resolve: None,
103 // }],
104 // depth_stencil: None,
105 // });
106 //
107 // // We can't free textures directly after the call to `execute_with_renderpass` as it freezes
108 // // the lifetime of `self` for the remainder of the closure. so we instead buffer the textures
109 // // to free for a frame so we can clean them up before the next call.
110 // let textures_to_free = mem::replace(&mut self.textures_to_free, mem::take(&mut input.textures_delta.free));
111 // let pt_handle = builder.passthrough_ref_mut(self);
112 //
113 // builder.build(move |pt, renderer, encoder_or_pass, _temps, _ready, _graph_data| {
114 // let this = pt.get_mut(pt_handle);
115 // let rpass = encoder_or_pass.get_rpass(rpass_handle);
116 //
117 // for tex in textures_to_free {
118 // this.internal.free_texture(&tex);
119 // }
120 // for (id, image_delta) in input.textures_delta.set {
121 // this.internal
122 // .update_texture(&renderer.device, &renderer.queue, id, &image_delta)
123 // }
124 //
125 // this.internal.update_buffers(
126 // &renderer.device,
127 // &renderer.queue,
128 // input.paint_jobs,
129 // &this.screen_descriptor,
130 // );
131 //
132 // this.internal
133 // .execute_with_renderpass(rpass, input.paint_jobs, &this.screen_descriptor);
134 // });
135 // }
136}