Move color indexing to vertex shader

Move more work to GPU from CPU. Some very non-scientific profiling
suggests this is implementation is more performant, but more work should
be done there.
This commit is contained in:
Joe Wilm 2016-10-24 10:59:25 -07:00
parent e9304afd36
commit 0958c0f0f2
2 changed files with 111 additions and 45 deletions

View File

@ -24,14 +24,16 @@ layout (location = 2) in vec4 glyph;
layout (location = 3) in vec4 uv;
// text fg color
layout (location = 4) in vec3 textColor;
layout (location = 4) in uvec4 textColor;
// Background color
layout (location = 5) in vec3 backgroundColor;
layout (location = 5) in uvec4 backgroundColor;
out vec2 TexCoords;
out vec3 fg;
out vec3 bg;
uniform vec3 colors[18];
// Terminal properties
uniform vec2 termDim;
uniform vec2 cellDim;
@ -73,6 +75,33 @@ void main()
}
background = backgroundPass;
bg = backgroundColor / vec3(255.0, 255.0, 255.0);
fg = textColor / vec3(255.0, 255.0, 255.0);
switch (textColor.x) {
case 0u:
// cell::Color::Rgb
fg = vec3(textColor.yzw) / vec3(255.0, 255.0, 255.0);
break;
case 1u:
// cell::Color::Ansi
fg = vec3(colors[textColor.y]);
break;
default:
// Should never happen; let's make it red
fg = vec3(1.0, 0.0, 0.0);
break;
}
switch (backgroundColor.x) {
case 0u:
// cell::Color::Rgb
bg = vec3(backgroundColor.yzw) / vec3(255.0, 255.0, 255.0);
break;
case 1u:
// cell::Color::Ansi
bg = vec3(colors[backgroundColor.y]);
break;
default:
// Should never happen; let's make it blue
bg = vec3(0.0, 0.0, 1.0);
break;
}
}

View File

@ -93,7 +93,12 @@ pub struct ShaderProgram {
/// Background pass flag
///
/// Rendering is split into two passes; 1 for backgrounds, and one for text
u_background: GLint
u_background: GLint,
/// Color uniforms
///
/// Ansi colors are uploaded to the GPU and indexed in the vertex shader
u_colors: [GLint; 18],
}
@ -224,6 +229,7 @@ impl GlyphCache {
}
#[derive(Debug)]
#[repr(C)]
struct InstanceData {
// coords
col: f32,
@ -241,13 +247,15 @@ struct InstanceData {
uv_width: f32,
uv_height: f32,
// color
r: f32,
g: f32,
b: f32,
disc: u32,
r: u32,
g: u32,
b: u32,
// background color
bg_r: f32,
bg_g: f32,
bg_b: f32,
bg_disc: u32,
bg_r: u32,
bg_g: u32,
bg_b: u32,
}
#[derive(Debug)]
@ -260,6 +268,7 @@ pub struct QuadRenderer {
atlas: Vec<Atlas>,
active_tex: GLuint,
batch: Batch,
colors: [Rgb; 18],
rx: mpsc::Receiver<Msg>,
}
@ -303,17 +312,8 @@ impl Batch {
self.tex = glyph.tex_id;
}
// TODO move colors list to uniform buffer and do this indexing in vertex shader
let fg = match cell.fg {
::term::cell::Color::Rgb(rgb) => rgb,
::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] },
};
// TODO move colors list to uniform buffer and do this indexing in vertex shader
let bg = match cell.bg {
::term::cell::Color::Rgb(rgb) => rgb,
::term::cell::Color::Ansi(ansi) => unsafe { COLORS[ansi as usize] },
};
let fg: &[u8; 4] = unsafe { ::std::mem::transmute(&cell.fg) };
let bg: &[u8; 4] = unsafe { ::std::mem::transmute(&cell.bg) };
let mut instance = InstanceData {
col: col,
@ -329,23 +329,27 @@ impl Batch {
uv_width: glyph.uv_width,
uv_height: glyph.uv_height,
r: fg.r as f32,
g: fg.g as f32,
b: fg.b as f32,
disc: fg[0] as u32,
r: fg[1] as u32,
g: fg[2] as u32,
b: fg[3] as u32,
bg_r: bg.r as f32,
bg_g: bg.g as f32,
bg_b: bg.b as f32,
bg_disc: bg[0] as u32,
bg_r: bg[1] as u32,
bg_g: bg[2] as u32,
bg_b: bg[3] as u32,
};
if cell.flags.contains(cell::INVERSE) {
instance.r = bg.r as f32;
instance.g = bg.g as f32;
instance.b = bg.b as f32;
instance.disc = bg[0] as u32;
instance.r = bg[1] as u32;
instance.g = bg[2] as u32;
instance.b = bg[3] as u32;
instance.bg_r = fg.r as f32;
instance.bg_g = fg.g as f32;
instance.bg_b = fg.b as f32;
instance.bg_disc = fg[0] as u32;
instance.bg_r = fg[1] as u32;
instance.bg_g = fg[2] as u32;
instance.bg_b = fg[3] as u32;
}
self.instances.push(instance);
@ -389,7 +393,8 @@ const ATLAS_SIZE: i32 = 1024;
impl QuadRenderer {
// TODO should probably hand this a transform instead of width/height
pub fn new(config: &Config, width: u32, height: u32) -> QuadRenderer {
let program = ShaderProgram::new(width, height).unwrap();
let colors = config.color_list();
let program = ShaderProgram::new(&colors, width, height).unwrap();
let mut vao: GLuint = 0;
let mut vbo: GLuint = 0;
@ -470,17 +475,17 @@ impl QuadRenderer {
gl::EnableVertexAttribArray(3);
gl::VertexAttribDivisor(3, 1);
// color
gl::VertexAttribPointer(4, 3,
gl::FLOAT, gl::FALSE,
gl::VertexAttribIPointer(4, 4,
gl::UNSIGNED_INT,
size_of::<InstanceData>() as i32,
(10 * size_of::<f32>()) as *const _);
gl::EnableVertexAttribArray(4);
gl::VertexAttribDivisor(4, 1);
// color
gl::VertexAttribPointer(5, 3,
gl::FLOAT, gl::FALSE,
gl::VertexAttribIPointer(5, 4,
gl::UNSIGNED_INT,
size_of::<InstanceData>() as i32,
(13 * size_of::<f32>()) as *const _);
(14 * size_of::<f32>()) as *const _);
gl::EnableVertexAttribArray(5);
gl::VertexAttribDivisor(5, 1);
@ -536,6 +541,7 @@ impl QuadRenderer {
atlas: Vec::new(),
active_tex: 0,
batch: Batch::new(),
colors: config.color_list(),
rx: msg_rx,
};
@ -555,9 +561,10 @@ impl QuadRenderer {
while let Ok(msg) = self.rx.try_recv() {
match msg {
Msg::ConfigReload(config) => {
unsafe {
COLORS = config.color_list();
}
self.colors = config.color_list();
self.program.activate();
self.program.set_color_uniforms(&self.colors);
self.program.deactivate();
},
Msg::ShaderReload => {
self.reload_shaders(props.width as u32, props.height as u32);
@ -607,7 +614,7 @@ impl QuadRenderer {
}
pub fn reload_shaders(&mut self, width: u32, height: u32) {
let program = match ShaderProgram::new(width, height) {
let program = match ShaderProgram::new(&self.colors, width, height) {
Ok(program) => program,
Err(err) => {
match err {
@ -826,7 +833,11 @@ impl ShaderProgram {
}
}
pub fn new(width: u32, height: u32) -> Result<ShaderProgram, ShaderCreationError> {
pub fn new(
colors: &[Rgb; 18],
width: u32,
height: u32
) -> Result<ShaderProgram, ShaderCreationError> {
let vertex_shader = ShaderProgram::create_shader(TEXT_SHADER_V_PATH, gl::VERTEX_SHADER)?;
let fragment_shader = ShaderProgram::create_shader(TEXT_SHADER_F_PATH,
gl::FRAGMENT_SHADER)?;
@ -864,8 +875,19 @@ impl ShaderProgram {
assert_uniform_valid!(projection, term_dim, cell_dim);
let mut color_uniforms: [GLint; 18] = unsafe { ::std::mem::uninitialized() };
for i in 0..18 {
color_uniforms[i] = unsafe {
let s = format!("colors[{}]\0", i).into_bytes();
gl::GetUniformLocation(program, cptr!(&s[..]))
};
assert_uniform_valid!(color_uniforms[i]);
}
let shader = ShaderProgram {
id: program,
u_colors: color_uniforms,
u_projection: projection,
u_term_dim: term_dim,
u_cell_dim: cell_dim,
@ -873,6 +895,7 @@ impl ShaderProgram {
};
shader.update_projection(width as f32, height as f32);
shader.set_color_uniforms(colors);
shader.deactivate();
@ -893,6 +916,20 @@ impl ShaderProgram {
}
fn set_color_uniforms(&self, colors: &[Rgb; 18]) {
println!("setting colors: {:#?}", colors);
for (i, rgb) in colors.iter().enumerate() {
unsafe {
gl::Uniform3f(
self.u_colors[i],
rgb.r as f32 / 255.0,
rgb.g as f32 / 255.0,
rgb.b as f32 / 255.0,
);
}
}
}
fn set_term_uniforms(&self, props: &term::SizeInfo) {
unsafe {
gl::Uniform2f(self.u_term_dim, props.width, props.height);