par_term_render/cell_renderer/
render.rs1use super::CellRenderer;
2use anyhow::Result;
3
4impl CellRenderer {
5 pub(crate) fn emit_three_phase_draw_calls(
16 &self,
17 render_pass: &mut wgpu::RenderPass<'_>,
18 cursor_overlay_start: u32,
19 cursor_overlay_end: u32,
20 ) {
21 render_pass.set_pipeline(&self.pipelines.bg_pipeline);
23 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
24 render_pass.set_vertex_buffer(1, self.buffers.bg_instance_buffer.slice(..));
25 render_pass.draw(0..4, 0..cursor_overlay_start);
26
27 if cursor_overlay_end < self.buffers.actual_bg_instances as u32 {
30 render_pass.draw(
31 0..4,
32 cursor_overlay_end..self.buffers.actual_bg_instances as u32,
33 );
34 }
35
36 render_pass.set_pipeline(&self.pipelines.text_pipeline);
38 render_pass.set_bind_group(0, &self.pipelines.text_bind_group, &[]);
39 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
40 render_pass.set_vertex_buffer(1, self.buffers.text_instance_buffer.slice(..));
41 render_pass.draw(0..4, 0..self.buffers.actual_text_instances as u32);
42
43 if cursor_overlay_start < cursor_overlay_end {
45 render_pass.set_pipeline(&self.pipelines.bg_pipeline);
46 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
47 render_pass.set_vertex_buffer(1, self.buffers.bg_instance_buffer.slice(..));
48 render_pass.draw(0..4, cursor_overlay_start..cursor_overlay_end);
49 }
50 }
51
52 pub fn render_to_texture(
62 &mut self,
63 target_view: &wgpu::TextureView,
64 skip_background_image: bool,
65 ) -> Result<wgpu::SurfaceTexture> {
66 let output = self.surface.get_current_texture()?;
67 self.build_instance_buffers()?;
68
69 let render_background_image =
72 !skip_background_image && self.pipelines.bg_image_bind_group.is_some();
73
74 if render_background_image {
75 self.update_bg_image_uniforms(Some(1.0));
80 }
81
82 let mut encoder = self
83 .device
84 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
85 label: Some("render to texture encoder"),
86 });
87
88 let clear_color = wgpu::Color::TRANSPARENT;
90
91 {
92 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
93 label: Some("render pass"),
94 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
95 view: target_view,
96 resolve_target: None,
97 ops: wgpu::Operations {
98 load: wgpu::LoadOp::Clear(clear_color),
99 store: wgpu::StoreOp::Store,
100 },
101 depth_slice: None,
102 })],
103 depth_stencil_attachment: None,
104 timestamp_writes: None,
105 occlusion_query_set: None,
106 });
107
108 if render_background_image
110 && let Some(ref bg_bind_group) = self.pipelines.bg_image_bind_group
111 {
112 render_pass.set_pipeline(&self.pipelines.bg_image_pipeline);
113 render_pass.set_bind_group(0, bg_bind_group, &[]);
114 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
115 render_pass.draw(0..4, 0..1);
116 }
117
118 let cursor_overlay_start = (self.grid.cols * self.grid.rows) as u32;
119 let cursor_overlay_end =
120 cursor_overlay_start + super::instance_buffers::CURSOR_OVERLAY_SLOTS as u32;
121 self.emit_three_phase_draw_calls(
122 &mut render_pass,
123 cursor_overlay_start,
124 cursor_overlay_end,
125 );
126 }
127
128 self.queue.submit(std::iter::once(encoder.finish()));
129
130 if render_background_image {
134 self.update_bg_image_uniforms(None);
135 }
136
137 Ok(output)
138 }
139
140 pub fn render_background_only(
152 &self,
153 target_view: &wgpu::TextureView,
154 clear_first: bool,
155 ) -> Result<bool> {
156 let mut encoder = self
157 .device
158 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
159 label: Some("background only encoder"),
160 });
161
162 let use_bg_image_pipeline = self.pipelines.bg_image_bind_group.is_some();
165 let clear_color = if use_bg_image_pipeline {
166 wgpu::Color::TRANSPARENT
167 } else {
168 wgpu::Color {
169 r: self.background_color[0] as f64 * self.window_opacity as f64,
170 g: self.background_color[1] as f64 * self.window_opacity as f64,
171 b: self.background_color[2] as f64 * self.window_opacity as f64,
172 a: self.window_opacity as f64,
173 }
174 };
175
176 let load_op = if clear_first {
177 wgpu::LoadOp::Clear(clear_color)
178 } else {
179 wgpu::LoadOp::Load
180 };
181
182 {
183 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
184 label: Some("background only render pass"),
185 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
186 view: target_view,
187 resolve_target: None,
188 ops: wgpu::Operations {
189 load: load_op,
190 store: wgpu::StoreOp::Store,
191 },
192 depth_slice: None,
193 })],
194 depth_stencil_attachment: None,
195 timestamp_writes: None,
196 occlusion_query_set: None,
197 });
198
199 if use_bg_image_pipeline
201 && let Some(ref bg_bind_group) = self.pipelines.bg_image_bind_group
202 {
203 render_pass.set_pipeline(&self.pipelines.bg_image_pipeline);
204 render_pass.set_bind_group(0, bg_bind_group, &[]);
205 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
206 render_pass.draw(0..4, 0..1);
207 }
208 }
209
210 self.queue.submit(std::iter::once(encoder.finish()));
211 Ok(use_bg_image_pipeline)
212 }
213
214 pub fn render_to_view(&self, target_view: &wgpu::TextureView) -> Result<()> {
217 let mut encoder = self
221 .device
222 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
223 label: Some("screenshot render encoder"),
224 });
225
226 let use_bg_image_pipeline = self.pipelines.bg_image_bind_group.is_some();
228 let clear_color = if use_bg_image_pipeline {
229 wgpu::Color::TRANSPARENT
230 } else {
231 wgpu::Color {
232 r: self.background_color[0] as f64 * self.window_opacity as f64,
233 g: self.background_color[1] as f64 * self.window_opacity as f64,
234 b: self.background_color[2] as f64 * self.window_opacity as f64,
235 a: self.window_opacity as f64,
236 }
237 };
238
239 {
240 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
241 label: Some("screenshot render pass"),
242 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
243 view: target_view,
244 resolve_target: None,
245 ops: wgpu::Operations {
246 load: wgpu::LoadOp::Clear(clear_color),
247 store: wgpu::StoreOp::Store,
248 },
249 depth_slice: None,
250 })],
251 depth_stencil_attachment: None,
252 timestamp_writes: None,
253 occlusion_query_set: None,
254 });
255
256 if use_bg_image_pipeline
258 && let Some(ref bg_bind_group) = self.pipelines.bg_image_bind_group
259 {
260 render_pass.set_pipeline(&self.pipelines.bg_image_pipeline);
261 render_pass.set_bind_group(0, bg_bind_group, &[]);
262 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
263 render_pass.draw(0..4, 0..1);
264 }
265
266 let cursor_overlay_start = (self.grid.cols * self.grid.rows) as u32;
267 let cursor_overlay_end =
268 cursor_overlay_start + super::instance_buffers::CURSOR_OVERLAY_SLOTS as u32;
269 self.emit_three_phase_draw_calls(
270 &mut render_pass,
271 cursor_overlay_start,
272 cursor_overlay_end,
273 );
274
275 self.scrollbar.render(&mut render_pass);
277 }
278
279 self.queue.submit(std::iter::once(encoder.finish()));
280 Ok(())
281 }
282
283 pub fn render_overlays(
284 &mut self,
285 surface_texture: &wgpu::SurfaceTexture,
286 show_scrollbar: bool,
287 ) -> Result<()> {
288 if !show_scrollbar && self.visual_bell_intensity <= 0.0 {
290 return Ok(());
291 }
292
293 let view = surface_texture
294 .texture
295 .create_view(&wgpu::TextureViewDescriptor::default());
296 let mut encoder = self
297 .device
298 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
299 label: Some("overlay encoder"),
300 });
301
302 {
303 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
304 label: Some("overlay pass"),
305 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
306 view: &view,
307 resolve_target: None,
308 ops: wgpu::Operations {
309 load: wgpu::LoadOp::Load,
310 store: wgpu::StoreOp::Store,
311 },
312 depth_slice: None,
313 })],
314 depth_stencil_attachment: None,
315 timestamp_writes: None,
316 occlusion_query_set: None,
317 });
318
319 if show_scrollbar {
320 self.scrollbar.render(&mut render_pass);
321 }
322
323 if self.visual_bell_intensity > 0.0 {
324 let uniforms: [f32; 8] = [
327 -1.0, -1.0, 2.0, 2.0, self.visual_bell_color[0], self.visual_bell_color[1], self.visual_bell_color[2], self.visual_bell_intensity, ];
336 self.queue.write_buffer(
337 &self.buffers.visual_bell_uniform_buffer,
338 0,
339 bytemuck::cast_slice(&uniforms),
340 );
341
342 render_pass.set_pipeline(&self.pipelines.visual_bell_pipeline);
343 render_pass.set_bind_group(0, &self.pipelines.visual_bell_bind_group, &[]);
344 render_pass.draw(0..4, 0..1); }
346 }
347
348 self.queue.submit(std::iter::once(encoder.finish()));
349 Ok(())
350 }
351
352 pub fn render_opaque_alpha(&self, surface_texture: &wgpu::SurfaceTexture) -> Result<()> {
361 if self.window_opacity < 1.0 {
362 return Ok(());
363 }
364
365 let view = surface_texture
366 .texture
367 .create_view(&wgpu::TextureViewDescriptor::default());
368 let mut encoder = self
369 .device
370 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
371 label: Some("opaque alpha encoder"),
372 });
373
374 {
375 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
376 label: Some("opaque alpha pass"),
377 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
378 view: &view,
379 resolve_target: None,
380 ops: wgpu::Operations {
381 load: wgpu::LoadOp::Load,
382 store: wgpu::StoreOp::Store,
383 },
384 depth_slice: None,
385 })],
386 depth_stencil_attachment: None,
387 timestamp_writes: None,
388 occlusion_query_set: None,
389 });
390
391 render_pass.set_pipeline(&self.pipelines.opaque_alpha_pipeline);
392 render_pass.draw(0..3, 0..1);
393 }
394
395 self.queue.submit(std::iter::once(encoder.finish()));
396 Ok(())
397 }
398}