Merge pull request #93 from Kethku/build-draw-command-perf-improvements

profiling motivated perf improvements in build draw commands
macos-click-through
Keith Simmons 5 years ago committed by GitHub
commit 48d3824892
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,6 @@
use std::collections::HashMap;
use std::sync::Arc;
use skulpin::skia_safe::Color4f;
use super::style::{Style, Colors};
@ -39,7 +41,7 @@ pub struct Cursor {
pub blinkwait: Option<u64>,
pub blinkon: Option<u64>,
pub blinkoff: Option<u64>,
pub style: Option<Style>,
pub style: Option<Arc<Style>>,
pub enabled: bool,
pub mode_list: Vec<CursorMode>
}
@ -75,7 +77,7 @@ impl Cursor {
}
}
pub fn change_mode(&mut self, mode_index: u64, styles: &HashMap<u64, Style>) {
pub fn change_mode(&mut self, mode_index: u64, styles: &HashMap<u64, Arc<Style>>) {
if let Some(CursorMode { shape, style_id, cell_percentage, blinkwait, blinkon, blinkoff }) = self.mode_list.get(mode_index as usize) {
if let Some(shape) = shape {
self.shape = shape.clone();

@ -17,13 +17,14 @@ lazy_static! {
pub static ref EDITOR: Arc<Mutex<Editor>> = Arc::new(Mutex::new(Editor::new()));
}
pub type GridCell = Option<(String, Option<Style>)>;
pub type GridCell = Option<(String, Option<Arc<Style>>)>;
#[derive(new, Debug, Clone)]
pub struct DrawCommand {
pub text: String,
pub cell_width: u64,
pub grid_position: (u64, u64),
pub style: Option<Style>,
pub style: Option<Arc<Style>>,
#[new(value = "1")]
pub scale: u16
}
@ -38,9 +39,9 @@ pub struct Editor {
pub font_name: Option<String>,
pub font_size: Option<f32>,
pub cursor: Cursor,
pub default_colors: Colors,
pub defined_styles: HashMap<u64, Style>,
pub previous_style: Option<Style>
pub default_style: Arc<Style>,
pub defined_styles: HashMap<u64, Arc<Style>>,
pub previous_style: Option<Arc<Style>>
}
impl Editor {
@ -51,11 +52,11 @@ impl Editor {
should_clear: true,
title: "Neovide".to_string(),
cursor: Cursor::new(),
size: INITIAL_DIMENSIONS,
font_name: None,
font_size: None,
default_colors: Colors::new(Some(colors::WHITE), Some(colors::BLACK), Some(colors::GREY)),
cursor: Cursor::new(),
default_style: Arc::new(Style::new(Colors::new(Some(colors::WHITE), Some(colors::BLACK), Some(colors::GREY)))),
defined_styles: HashMap::new(),
previous_style: None
};
@ -74,8 +75,8 @@ impl Editor {
RedrawEvent::BusyStop => self.cursor.enabled = true,
RedrawEvent::Flush => REDRAW_SCHEDULER.queue_next_frame(),
RedrawEvent::Resize { width, height, .. } => self.resize((width, height)),
RedrawEvent::DefaultColorsSet { colors } => self.default_colors = colors,
RedrawEvent::HighlightAttributesDefine { id, style } => { self.defined_styles.insert(id, style); },
RedrawEvent::DefaultColorsSet { colors } => self.default_style = Arc::new(Style::new(colors)),
RedrawEvent::HighlightAttributesDefine { id, style } => { self.defined_styles.insert(id, Arc::new(style)); },
RedrawEvent::GridLine { row, column_start, cells, .. } => self.draw_grid_line(row, column_start, cells),
RedrawEvent::Clear { .. } => self.clear(),
RedrawEvent::CursorGoto { row, column, .. } => self.cursor.position = (row, column),
@ -95,34 +96,44 @@ impl Editor {
}
}
fn command_matches(command: &Option<DrawCommand>, style: &Option<Style>) -> bool {
fn command_matches(command: &Option<DrawCommand>, style: &Option<Arc<Style>>) -> bool {
match command {
Some(command) => &command.style == style,
None => true
}
}
fn add_character(command: &mut Option<DrawCommand>, character: &str, row_index: u64, col_index: u64, style: Option<Style>) {
fn add_character(command: &mut Option<DrawCommand>, character: &str, row_index: u64, col_index: u64, style: Option<Arc<Style>>) {
match command {
Some(command) => command.text.push_str(character),
Some(command) => {
command.text.push_str(character);
command.cell_width += 1;
},
None => {
command.replace(DrawCommand::new(character.to_string(), (col_index, row_index), style));
command.replace(DrawCommand::new(character.to_string(), 1, (col_index, row_index), style));
}
}
}
for (col_index, cell) in row.iter().enumerate() {
let (character, style) = cell.clone().unwrap_or_else(|| (' '.to_string(), Some(Style::new(self.default_colors.clone()))));
if character.is_empty() {
add_character(&mut command, &" ", row_index as u64, col_index as u64, style.clone());
add_command(&mut draw_commands, command);
command = None;
if let Some((character, style)) = cell {
if character.is_empty() {
add_character(&mut command, &" ", row_index as u64, col_index as u64, style.clone());
add_command(&mut draw_commands, command);
command = None;
} else {
if !command_matches(&command, &style) {
add_command(&mut draw_commands, command);
command = None;
}
add_character(&mut command, &character, row_index as u64, col_index as u64, style.clone());
}
} else {
if !command_matches(&command, &style) {
if !command_matches(&command, &None) {
add_command(&mut draw_commands, command);
command = None;
}
add_character(&mut command, &character, row_index as u64, col_index as u64, style.clone());
add_character(&mut command, " ", row_index as u64, col_index as u64, None);
}
}
add_command(&mut draw_commands, command);
@ -133,8 +144,10 @@ impl Editor {
let (x, y) = command.grid_position;
let dirty_row = &self.dirty[y as usize];
for char_index in 0..command.text.graphemes(true).count() {
if dirty_row[x as usize + char_index] {
let min = (x as i64 - 1).max(0) as u64;
let max = (x + command.cell_width + 1).min(dirty_row.len() as u64);
for char_index in min..max {
if dirty_row[char_index as usize] {
return true;
}
}

@ -1,3 +1,5 @@
use std::sync::Arc;
use skulpin::CoordinateSystemHelper;
use skulpin::skia_safe::{Canvas, Paint, Surface, Budgeted, Rect, colors};
use skulpin::skia_safe::gpu::SurfaceOrigin;
@ -42,44 +44,44 @@ impl Renderer {
self.font_height = font_height;
}
fn compute_text_region(&self, text: &str, grid_pos: (u64, u64), size: u16) -> Rect {
fn compute_text_region(&self, text: &str, grid_pos: (u64, u64), cell_width: u64, size: u16) -> Rect {
let (grid_x, grid_y) = grid_pos;
let x = grid_x as f32 * self.font_width;
let y = grid_y as f32 * self.font_height;
let width = text.graphemes(true).count() as f32 * self.font_width * size as f32;
let width = cell_width as f32 * self.font_width * size as f32;
let height = self.font_height * size as f32;
Rect::new(x, y, x + width, y + height)
}
fn draw_background(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), size: u16, style: &Option<Style>, default_colors: &Colors) {
let region = self.compute_text_region(text, grid_pos, size);
let style = style.clone().unwrap_or_else(|| Style::new(default_colors.clone()));
fn draw_background(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), cell_width:u64, size: u16, style: &Option<Arc<Style>>, default_style: &Arc<Style>) {
let region = self.compute_text_region(text, grid_pos, cell_width, size);
let style = style.as_ref().unwrap_or(default_style);
self.paint.set_color(style.background(default_colors).to_color());
self.paint.set_color(style.background(&default_style.colors).to_color());
canvas.draw_rect(region, &self.paint);
}
fn draw_foreground(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), size: u16, style: &Option<Style>, default_colors: &Colors) {
fn draw_foreground(&mut self, canvas: &mut Canvas, text: &str, grid_pos: (u64, u64), cell_width: u64, size: u16, style: &Option<Arc<Style>>, default_style: &Arc<Style>) {
let (grid_x, grid_y) = grid_pos;
let x = grid_x as f32 * self.font_width;
let y = grid_y as f32 * self.font_height;
let width = text.graphemes(true).count() as f32 * self.font_width;
let width = cell_width as f32 * self.font_width;
let style = style.clone().unwrap_or_else(|| Style::new(default_colors.clone()));
let style = style.as_ref().unwrap_or(default_style);
canvas.save();
let region = self.compute_text_region(text, grid_pos, size);
let region = self.compute_text_region(text, grid_pos, cell_width, size);
canvas.clip_rect(region, None, Some(false));
if style.underline || style.undercurl {
let line_position = self.shaper.underline_position();
self.paint.set_color(style.special(&default_colors).to_color());
self.paint.set_color(style.special(&default_style.colors).to_color());
canvas.draw_line((x, y - line_position + self.font_height), (x + width, y - line_position + self.font_height), &self.paint);
}
self.paint.set_color(style.foreground(&default_colors).to_color());
self.paint.set_color(style.foreground(&default_style.colors).to_color());
let text = text.trim_end();
if !text.is_empty() {
for blob in self.shaper.shape_cached(text, style.bold, style.italic).iter() {
@ -89,7 +91,7 @@ impl Renderer {
if style.strikethrough {
let line_position = region.center_y();
self.paint.set_color(style.special(&default_colors).to_color());
self.paint.set_color(style.special(&default_style.colors).to_color());
canvas.draw_line((x, line_position), (x + width, line_position), &self.paint);
}
@ -97,11 +99,11 @@ impl Renderer {
}
pub fn draw(&mut self, gpu_canvas: &mut Canvas, coordinate_system_helper: &CoordinateSystemHelper) -> bool {
let ((draw_commands, should_clear), default_colors, cursor, font_name, font_size) = {
let ((draw_commands, should_clear), default_style, cursor, font_name, font_size) = {
let mut editor = EDITOR.lock().unwrap();
(
editor.build_draw_commands(),
editor.default_colors.clone(),
editor.default_style.clone(),
editor.cursor.clone(),
editor.font_name.clone(),
editor.font_size
@ -126,7 +128,7 @@ impl Renderer {
let surface_origin = SurfaceOrigin::TopLeft;
let mut surface = Surface::new_render_target(&mut context, budgeted, &image_info, None, surface_origin, None, None).expect("Could not create surface");
let canvas = surface.canvas();
canvas.clear(default_colors.background.clone().unwrap().to_color());
canvas.clear(default_style.colors.background.clone().unwrap().to_color());
surface
});
@ -134,10 +136,10 @@ impl Renderer {
coordinate_system_helper.use_logical_coordinates(&mut canvas);
for command in draw_commands.iter() {
self.draw_background(&mut canvas, &command.text, command.grid_position.clone(), command.scale, &command.style, &default_colors);
self.draw_background(&mut canvas, &command.text, command.grid_position.clone(), command.cell_width, command.scale, &command.style, &default_style);
}
for command in draw_commands.iter() {
self.draw_foreground(&mut canvas, &command.text, command.grid_position.clone(), command.scale, &command.style, &default_colors);
self.draw_foreground(&mut canvas, &command.text, command.grid_position.clone(), command.cell_width, command.scale, &command.style, &default_style);
}
let image = surface.image_snapshot();
@ -148,7 +150,7 @@ impl Renderer {
self.surface = Some(surface);
self.cursor_renderer.draw(
cursor, &default_colors,
cursor, &default_style.colors,
self.font_width, self.font_height,
&mut self.paint, &mut self.shaper,
gpu_canvas);

Loading…
Cancel
Save