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 = match self.surface.get_current_texture() {
67 wgpu::CurrentSurfaceTexture::Success(t)
68 | wgpu::CurrentSurfaceTexture::Suboptimal(t) => t,
69 other => return Err(crate::error::RenderError::Surface(format!("{other:?}")).into()),
70 };
71 self.build_instance_buffers()?;
72
73 let render_background_image =
76 !skip_background_image && self.pipelines.bg_image_bind_group.is_some();
77
78 if render_background_image {
79 self.update_bg_image_uniforms(Some(1.0));
84 }
85
86 let mut encoder = self
87 .device
88 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
89 label: Some("render to texture encoder"),
90 });
91
92 let clear_color = wgpu::Color::TRANSPARENT;
94
95 {
96 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
97 label: Some("render pass"),
98 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
99 view: target_view,
100 resolve_target: None,
101 ops: wgpu::Operations {
102 load: wgpu::LoadOp::Clear(clear_color),
103 store: wgpu::StoreOp::Store,
104 },
105 depth_slice: None,
106 })],
107 depth_stencil_attachment: None,
108 timestamp_writes: None,
109 occlusion_query_set: None,
110 multiview_mask: None,
111 });
112
113 if render_background_image
115 && let Some(ref bg_bind_group) = self.pipelines.bg_image_bind_group
116 {
117 render_pass.set_pipeline(&self.pipelines.bg_image_pipeline);
118 render_pass.set_bind_group(0, bg_bind_group, &[]);
119 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
120 render_pass.draw(0..4, 0..1);
121 }
122
123 let cursor_overlay_start = (self.grid.cols * self.grid.rows) as u32;
124 let cursor_overlay_end =
125 cursor_overlay_start + super::instance_buffers::CURSOR_OVERLAY_SLOTS as u32;
126 self.emit_three_phase_draw_calls(
127 &mut render_pass,
128 cursor_overlay_start,
129 cursor_overlay_end,
130 );
131 }
132
133 self.queue.submit(std::iter::once(encoder.finish()));
134
135 if render_background_image {
139 self.update_bg_image_uniforms(None);
140 }
141
142 Ok(output)
143 }
144
145 pub fn render_background_only(
157 &self,
158 target_view: &wgpu::TextureView,
159 clear_first: bool,
160 ) -> Result<bool> {
161 let mut encoder = self
162 .device
163 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
164 label: Some("background only encoder"),
165 });
166
167 let use_bg_image_pipeline = self.pipelines.bg_image_bind_group.is_some();
170 let clear_color = if use_bg_image_pipeline {
171 wgpu::Color::TRANSPARENT
172 } else {
173 wgpu::Color {
174 r: self.background_color[0] as f64 * self.window_opacity as f64,
175 g: self.background_color[1] as f64 * self.window_opacity as f64,
176 b: self.background_color[2] as f64 * self.window_opacity as f64,
177 a: self.window_opacity as f64,
178 }
179 };
180
181 let load_op = if clear_first {
182 wgpu::LoadOp::Clear(clear_color)
183 } else {
184 wgpu::LoadOp::Load
185 };
186
187 {
188 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
189 label: Some("background only render pass"),
190 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
191 view: target_view,
192 resolve_target: None,
193 ops: wgpu::Operations {
194 load: load_op,
195 store: wgpu::StoreOp::Store,
196 },
197 depth_slice: None,
198 })],
199 depth_stencil_attachment: None,
200 timestamp_writes: None,
201 occlusion_query_set: None,
202 multiview_mask: None,
203 });
204
205 if use_bg_image_pipeline
207 && let Some(ref bg_bind_group) = self.pipelines.bg_image_bind_group
208 {
209 render_pass.set_pipeline(&self.pipelines.bg_image_pipeline);
210 render_pass.set_bind_group(0, bg_bind_group, &[]);
211 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
212 render_pass.draw(0..4, 0..1);
213 }
214 }
215
216 self.queue.submit(std::iter::once(encoder.finish()));
217 Ok(use_bg_image_pipeline)
218 }
219
220 pub fn render_to_view(&self, target_view: &wgpu::TextureView) -> Result<()> {
223 let mut encoder = self
227 .device
228 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
229 label: Some("screenshot render encoder"),
230 });
231
232 let use_bg_image_pipeline = self.pipelines.bg_image_bind_group.is_some();
234 let clear_color = if use_bg_image_pipeline {
235 wgpu::Color::TRANSPARENT
236 } else {
237 wgpu::Color {
238 r: self.background_color[0] as f64 * self.window_opacity as f64,
239 g: self.background_color[1] as f64 * self.window_opacity as f64,
240 b: self.background_color[2] as f64 * self.window_opacity as f64,
241 a: self.window_opacity as f64,
242 }
243 };
244
245 {
246 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
247 label: Some("screenshot render pass"),
248 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
249 view: target_view,
250 resolve_target: None,
251 ops: wgpu::Operations {
252 load: wgpu::LoadOp::Clear(clear_color),
253 store: wgpu::StoreOp::Store,
254 },
255 depth_slice: None,
256 })],
257 depth_stencil_attachment: None,
258 timestamp_writes: None,
259 occlusion_query_set: None,
260 multiview_mask: None,
261 });
262
263 if use_bg_image_pipeline
265 && let Some(ref bg_bind_group) = self.pipelines.bg_image_bind_group
266 {
267 render_pass.set_pipeline(&self.pipelines.bg_image_pipeline);
268 render_pass.set_bind_group(0, bg_bind_group, &[]);
269 render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
270 render_pass.draw(0..4, 0..1);
271 }
272
273 let cursor_overlay_start = (self.grid.cols * self.grid.rows) as u32;
274 let cursor_overlay_end =
275 cursor_overlay_start + super::instance_buffers::CURSOR_OVERLAY_SLOTS as u32;
276 self.emit_three_phase_draw_calls(
277 &mut render_pass,
278 cursor_overlay_start,
279 cursor_overlay_end,
280 );
281
282 self.scrollbar.render(&mut render_pass);
284 }
285
286 self.queue.submit(std::iter::once(encoder.finish()));
287 Ok(())
288 }
289
290 pub fn render_overlays(
291 &mut self,
292 surface_texture: &wgpu::SurfaceTexture,
293 show_scrollbar: bool,
294 ) -> Result<()> {
295 if !show_scrollbar && self.visual_bell_intensity <= 0.0 {
297 return Ok(());
298 }
299
300 let view = surface_texture
301 .texture
302 .create_view(&wgpu::TextureViewDescriptor::default());
303 let mut encoder = self
304 .device
305 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
306 label: Some("overlay encoder"),
307 });
308
309 {
310 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
311 label: Some("overlay pass"),
312 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
313 view: &view,
314 resolve_target: None,
315 ops: wgpu::Operations {
316 load: wgpu::LoadOp::Load,
317 store: wgpu::StoreOp::Store,
318 },
319 depth_slice: None,
320 })],
321 depth_stencil_attachment: None,
322 timestamp_writes: None,
323 occlusion_query_set: None,
324 multiview_mask: None,
325 });
326
327 if show_scrollbar {
328 self.scrollbar.render(&mut render_pass);
329 }
330
331 if self.visual_bell_intensity > 0.0 {
332 let uniforms: [f32; 8] = [
335 -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, ];
344 self.queue.write_buffer(
345 &self.buffers.visual_bell_uniform_buffer,
346 0,
347 bytemuck::cast_slice(&uniforms),
348 );
349
350 render_pass.set_pipeline(&self.pipelines.visual_bell_pipeline);
351 render_pass.set_bind_group(0, &self.pipelines.visual_bell_bind_group, &[]);
352 render_pass.draw(0..4, 0..1); }
354 }
355
356 self.queue.submit(std::iter::once(encoder.finish()));
357 Ok(())
358 }
359
360 pub fn render_opaque_alpha(&self, surface_texture: &wgpu::SurfaceTexture) -> Result<()> {
369 if self.window_opacity < 1.0 {
370 return Ok(());
371 }
372
373 let view = surface_texture
374 .texture
375 .create_view(&wgpu::TextureViewDescriptor::default());
376 let mut encoder = self
377 .device
378 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
379 label: Some("opaque alpha encoder"),
380 });
381
382 {
383 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
384 label: Some("opaque alpha pass"),
385 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
386 view: &view,
387 resolve_target: None,
388 ops: wgpu::Operations {
389 load: wgpu::LoadOp::Load,
390 store: wgpu::StoreOp::Store,
391 },
392 depth_slice: None,
393 })],
394 depth_stencil_attachment: None,
395 timestamp_writes: None,
396 occlusion_query_set: None,
397 multiview_mask: None,
398 });
399
400 render_pass.set_pipeline(&self.pipelines.opaque_alpha_pipeline);
401 render_pass.draw(0..3, 0..1);
402 }
403
404 self.queue.submit(std::iter::once(encoder.finish()));
405 Ok(())
406 }
407}