use super::super::CellRenderer;
use super::super::render::ThreePhaseRanges;
use super::{PaneInstanceBuildParams, PaneRenderViewParams};
use anyhow::Result;
pub(crate) struct PreparedPane {
scissor: (u32, u32, u32, u32),
clear_color: Option<wgpu::Color>,
pane_bg_index: Option<usize>,
ranges: ThreePhaseRanges,
scrollbar_slot: Option<usize>,
}
impl CellRenderer {
pub(crate) fn prepare_pane(
&mut self,
pane_index: usize,
p: PaneRenderViewParams<'_>,
) -> Result<PreparedPane> {
let PaneRenderViewParams {
viewport,
cells,
cols,
rows,
cursor_pos,
cursor_opacity,
show_scrollbar,
clear_first,
skip_background_image,
fill_default_bg_cells,
separator_marks,
pane_background,
} = p;
let ranges = self.build_pane_instance_buffers(PaneInstanceBuildParams {
viewport,
cells,
cols,
rows,
cursor_pos,
cursor_opacity,
skip_solid_background: skip_background_image,
fill_default_bg_cells,
separator_marks,
})?;
let pane_bg_index = if let Some(pane_bg) = pane_background
&& let Some(ref path) = pane_bg.image_path
&& self.bg_state.pane_bg_cache.contains_key(path.as_str())
{
self.prepare_pane_bg_bind_group(
pane_index,
path.as_str(),
super::super::background::PaneBgBindGroupParams {
pane_x: viewport.x,
pane_y: viewport.y,
pane_width: viewport.width,
pane_height: viewport.height,
mode: pane_bg.mode,
opacity: pane_bg.opacity,
darken: pane_bg.darken,
},
);
Some(pane_index)
} else {
None
};
let clear_color = clear_first.then(|| {
let base: [f32; 3] = if self.bg_state.bg_is_solid_color {
self.bg_state.solid_bg_color
} else {
[
self.background_color[0],
self.background_color[1],
self.background_color[2],
]
};
let alpha = self.window_opacity as f64 * viewport.opacity as f64;
wgpu::Color {
r: base[0] as f64 * alpha,
g: base[1] as f64 * alpha,
b: base[2] as f64 * alpha,
a: alpha,
}
});
Ok(PreparedPane {
scissor: viewport.to_scissor_rect(),
clear_color,
pane_bg_index,
ranges: ThreePhaseRanges::for_pane(ranges.bg, ranges.cursor_overlays, ranges.text),
scrollbar_slot: show_scrollbar.then_some(pane_index),
})
}
pub(crate) fn draw_prepared_panes(
&self,
surface_view: &wgpu::TextureView,
panes: &[PreparedPane],
) {
if panes.is_empty() {
return;
}
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("pane batch encoder"),
});
for pane in panes {
let load = match pane.clear_color {
Some(color) => wgpu::LoadOp::Clear(color),
None => wgpu::LoadOp::Load,
};
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("pane render pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: surface_view,
resolve_target: None,
ops: wgpu::Operations {
load,
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
let (sx, sy, sw, sh) = pane.scissor;
render_pass.set_scissor_rect(sx, sy, sw, sh);
if let Some(index) = pane.pane_bg_index
&& let Some(cached) = self.bg_state.pane_bg_uniform_cache.get(&index)
{
render_pass.set_pipeline(&self.pipelines.bg_image_pipeline);
render_pass.set_bind_group(0, &cached.bind_group, &[]);
render_pass.set_vertex_buffer(0, self.buffers.vertex_buffer.slice(..));
render_pass.draw(0..4, 0..1);
}
self.emit_three_phase_draw_calls(&mut render_pass, &pane.ranges);
if let Some(slot) = pane.scrollbar_slot {
render_pass.set_scissor_rect(0, 0, self.config.width, self.config.height);
self.scrollbar.render(&mut render_pass, slot);
}
}
self.queue.submit(std::iter::once(encoder.finish()));
}
pub fn render_pane_to_view(
&mut self,
surface_view: &wgpu::TextureView,
p: PaneRenderViewParams<'_>,
) -> Result<()> {
let (bg, text) = super::pane_instance_capacity(p.cols, p.rows);
self.begin_pane_batch(bg, text);
let prepared = self.prepare_pane(0, p)?;
self.draw_prepared_panes(surface_view, std::slice::from_ref(&prepared));
Ok(())
}
}