2022-03-02 10:05:12 +00:00
|
|
|
use std::ffi::CStr;
|
|
|
|
use std::fmt;
|
2016-02-26 04:59:21 +00:00
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
use crossfont::Metrics;
|
|
|
|
use log::info;
|
2018-12-22 17:16:54 +00:00
|
|
|
|
2021-01-01 05:19:03 +00:00
|
|
|
use alacritty_terminal::index::Point;
|
2020-11-05 04:45:14 +00:00
|
|
|
use alacritty_terminal::term::cell::Flags;
|
2019-11-23 17:08:52 +00:00
|
|
|
use alacritty_terminal::term::color::Rgb;
|
2018-12-22 17:16:54 +00:00
|
|
|
|
2021-01-24 21:45:36 +00:00
|
|
|
use crate::display::content::RenderableCell;
|
2022-04-06 10:06:39 +00:00
|
|
|
use crate::display::SizeInfo;
|
2020-07-18 01:27:41 +00:00
|
|
|
use crate::gl;
|
2020-12-10 06:38:32 +00:00
|
|
|
use crate::renderer::rects::{RectRenderer, RenderRect};
|
2022-03-02 10:05:12 +00:00
|
|
|
use crate::renderer::shader::ShaderError;
|
2020-07-18 01:27:41 +00:00
|
|
|
|
|
|
|
pub mod rects;
|
2022-01-30 20:57:25 +00:00
|
|
|
mod shader;
|
2022-03-02 10:05:12 +00:00
|
|
|
mod text;
|
|
|
|
|
|
|
|
pub use text::{GlyphCache, LoaderApi};
|
|
|
|
|
|
|
|
use shader::ShaderVersion;
|
|
|
|
use text::{Gles2Renderer, Glsl3Renderer, TextRenderer};
|
2022-01-30 20:57:25 +00:00
|
|
|
|
|
|
|
macro_rules! cstr {
|
|
|
|
($s:literal) => {
|
|
|
|
// This can be optimized into an no-op with pre-allocated NUL-terminated bytes.
|
|
|
|
unsafe { std::ffi::CStr::from_ptr(concat!($s, "\0").as_ptr().cast()) }
|
|
|
|
};
|
|
|
|
}
|
2022-02-08 17:47:31 +00:00
|
|
|
pub(crate) use cstr;
|
2020-07-11 17:03:09 +00:00
|
|
|
|
2017-01-02 03:19:15 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum Error {
|
2022-01-30 20:57:25 +00:00
|
|
|
/// Shader error.
|
|
|
|
Shader(ShaderError),
|
2017-01-02 03:19:15 +00:00
|
|
|
}
|
|
|
|
|
2020-01-03 00:17:22 +00:00
|
|
|
impl std::error::Error for Error {
|
|
|
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
|
|
match self {
|
2022-01-30 20:57:25 +00:00
|
|
|
Error::Shader(err) => err.source(),
|
2017-01-02 03:19:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-30 20:57:25 +00:00
|
|
|
impl fmt::Display for Error {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2020-01-21 22:36:44 +00:00
|
|
|
match self {
|
2022-01-30 20:57:25 +00:00
|
|
|
Error::Shader(err) => {
|
2020-01-21 22:36:44 +00:00
|
|
|
write!(f, "There was an error initializing the shaders: {}", err)
|
|
|
|
},
|
|
|
|
}
|
2017-01-02 03:19:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-30 20:57:25 +00:00
|
|
|
impl From<ShaderError> for Error {
|
|
|
|
fn from(val: ShaderError) -> Self {
|
|
|
|
Error::Shader(val)
|
2017-01-02 03:19:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-05 04:26:28 +00:00
|
|
|
#[derive(Debug)]
|
2022-03-02 10:05:12 +00:00
|
|
|
enum TextRendererProvider {
|
|
|
|
Gles2(Gles2Renderer),
|
|
|
|
Glsl3(Glsl3Renderer),
|
2016-06-05 04:26:28 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Renderer {
|
|
|
|
text_renderer: TextRendererProvider,
|
|
|
|
rect_renderer: RectRenderer,
|
2016-06-06 21:31:12 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
impl Renderer {
|
|
|
|
/// Create a new renderer.
|
2020-12-23 22:28:41 +00:00
|
|
|
///
|
2022-03-02 10:05:12 +00:00
|
|
|
/// This will automatically pick between the GLES2 and GLSL3 renderer based on the GPU's
|
|
|
|
/// supported OpenGL version.
|
|
|
|
pub fn new() -> Result<Self, Error> {
|
|
|
|
let (version, renderer) = unsafe {
|
|
|
|
let renderer = CStr::from_ptr(gl::GetString(gl::RENDERER) as *mut _);
|
|
|
|
let version = CStr::from_ptr(gl::GetString(gl::SHADING_LANGUAGE_VERSION) as *mut _);
|
|
|
|
(version.to_string_lossy(), renderer.to_string_lossy())
|
2020-12-29 00:05:18 +00:00
|
|
|
};
|
2020-12-23 22:28:41 +00:00
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
info!("Running on {}", renderer);
|
2020-12-29 00:05:18 +00:00
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
let (text_renderer, rect_renderer) = if version.as_ref() >= "3.3" {
|
|
|
|
let text_renderer = TextRendererProvider::Glsl3(Glsl3Renderer::new()?);
|
|
|
|
let rect_renderer = RectRenderer::new(ShaderVersion::Glsl3)?;
|
|
|
|
(text_renderer, rect_renderer)
|
|
|
|
} else {
|
|
|
|
let text_renderer = TextRendererProvider::Gles2(Gles2Renderer::new()?);
|
|
|
|
let rect_renderer = RectRenderer::new(ShaderVersion::Gles2)?;
|
|
|
|
(text_renderer, rect_renderer)
|
2020-12-29 00:05:18 +00:00
|
|
|
};
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
Ok(Self { text_renderer, rect_renderer })
|
2020-12-23 22:28:41 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
pub fn draw_cells<I: Iterator<Item = RenderableCell>>(
|
|
|
|
&mut self,
|
|
|
|
size_info: &SizeInfo,
|
|
|
|
glyph_cache: &mut GlyphCache,
|
|
|
|
cells: I,
|
|
|
|
) {
|
|
|
|
match &mut self.text_renderer {
|
|
|
|
TextRendererProvider::Gles2(renderer) => {
|
|
|
|
renderer.draw_cells(size_info, glyph_cache, cells)
|
|
|
|
},
|
|
|
|
TextRendererProvider::Glsl3(renderer) => {
|
|
|
|
renderer.draw_cells(size_info, glyph_cache, cells)
|
|
|
|
},
|
2020-12-29 00:05:18 +00:00
|
|
|
}
|
2020-04-15 03:50:34 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
/// Draw a string in a variable location. Used for printing the render timer, warnings and
|
|
|
|
/// errors.
|
|
|
|
pub fn draw_string(
|
2017-10-15 01:58:19 +00:00
|
|
|
&mut self,
|
2022-03-02 10:05:12 +00:00
|
|
|
point: Point<usize>,
|
|
|
|
fg: Rgb,
|
|
|
|
bg: Rgb,
|
|
|
|
string: &str,
|
|
|
|
size_info: &SizeInfo,
|
|
|
|
glyph_cache: &mut GlyphCache,
|
|
|
|
) {
|
|
|
|
let cells = string.chars().enumerate().map(|(i, character)| RenderableCell {
|
|
|
|
point: Point::new(point.line, point.column + i),
|
|
|
|
character,
|
|
|
|
zerowidth: None,
|
|
|
|
flags: Flags::empty(),
|
|
|
|
bg_alpha: 1.0,
|
|
|
|
fg,
|
|
|
|
bg,
|
2022-03-16 16:27:55 +00:00
|
|
|
underline: fg,
|
2016-11-28 22:13:11 +00:00
|
|
|
});
|
2016-06-05 04:26:28 +00:00
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
self.draw_cells(size_info, glyph_cache, cells);
|
2016-06-05 04:26:28 +00:00
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
pub fn with_loader<F, T>(&mut self, func: F) -> T
|
|
|
|
where
|
|
|
|
F: FnOnce(LoaderApi<'_>) -> T,
|
|
|
|
{
|
|
|
|
match &mut self.text_renderer {
|
|
|
|
TextRendererProvider::Gles2(renderer) => renderer.with_loader(func),
|
|
|
|
TextRendererProvider::Glsl3(renderer) => renderer.with_loader(func),
|
2016-02-26 04:59:21 +00:00
|
|
|
}
|
2016-06-03 03:27:07 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 22:50:23 +00:00
|
|
|
/// Draw all rectangles simultaneously to prevent excessive program swaps.
|
2022-02-08 17:47:31 +00:00
|
|
|
pub fn draw_rects(&mut self, size_info: &SizeInfo, metrics: &Metrics, rects: Vec<RenderRect>) {
|
2020-12-10 05:42:03 +00:00
|
|
|
if rects.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
2018-12-17 19:06:07 +00:00
|
|
|
|
2020-12-10 05:42:03 +00:00
|
|
|
// Prepare rect rendering state.
|
|
|
|
unsafe {
|
2020-05-05 22:50:23 +00:00
|
|
|
// Remove padding from viewport.
|
2020-12-10 05:42:03 +00:00
|
|
|
gl::Viewport(0, 0, size_info.width() as i32, size_info.height() as i32);
|
2019-10-26 19:45:47 +00:00
|
|
|
gl::BlendFuncSeparate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, gl::SRC_ALPHA, gl::ONE);
|
2018-12-17 19:06:07 +00:00
|
|
|
}
|
|
|
|
|
2022-02-08 17:47:31 +00:00
|
|
|
self.rect_renderer.draw(size_info, metrics, rects);
|
2018-12-22 17:16:54 +00:00
|
|
|
|
2020-12-10 05:42:03 +00:00
|
|
|
// Activate regular state again.
|
2018-12-17 19:06:07 +00:00
|
|
|
unsafe {
|
2020-05-05 22:50:23 +00:00
|
|
|
// Reset blending strategy.
|
2018-12-17 19:06:07 +00:00
|
|
|
gl::BlendFunc(gl::SRC1_COLOR, gl::ONE_MINUS_SRC1_COLOR);
|
|
|
|
|
2020-12-10 05:42:03 +00:00
|
|
|
// Restore viewport with padding.
|
2021-11-22 18:34:09 +00:00
|
|
|
self.set_viewport(size_info);
|
2018-12-17 19:06:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
/// Fill the window with `color` and `alpha`.
|
|
|
|
pub fn clear(&self, color: Rgb, alpha: f32) {
|
2016-02-26 04:59:21 +00:00
|
|
|
unsafe {
|
2016-11-28 22:13:11 +00:00
|
|
|
gl::ClearColor(
|
2018-12-17 19:06:07 +00:00
|
|
|
(f32::from(color.r) / 255.0).min(1.0) * alpha,
|
|
|
|
(f32::from(color.g) / 255.0).min(1.0) * alpha,
|
|
|
|
(f32::from(color.b) / 255.0).min(1.0) * alpha,
|
|
|
|
alpha,
|
|
|
|
);
|
2016-11-28 22:13:11 +00:00
|
|
|
gl::Clear(gl::COLOR_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-27 14:46:52 +00:00
|
|
|
#[cfg(not(any(target_os = "macos", windows)))]
|
2020-05-01 20:57:25 +00:00
|
|
|
pub fn finish(&self) {
|
|
|
|
unsafe {
|
|
|
|
gl::Finish();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
/// Set the viewport for cell rendering.
|
2016-06-06 20:20:35 +00:00
|
|
|
#[inline]
|
2022-03-02 10:05:12 +00:00
|
|
|
pub fn set_viewport(&self, size: &SizeInfo) {
|
2016-06-03 05:14:55 +00:00
|
|
|
unsafe {
|
2022-03-02 10:05:12 +00:00
|
|
|
gl::Viewport(
|
|
|
|
size.padding_x() as i32,
|
|
|
|
size.padding_y() as i32,
|
|
|
|
size.width() as i32 - 2 * size.padding_x() as i32,
|
|
|
|
size.height() as i32 - 2 * size.padding_y() as i32,
|
2016-06-03 05:14:55 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-02 10:05:12 +00:00
|
|
|
/// Resize the renderer.
|
|
|
|
pub fn resize(&self, size_info: &SizeInfo) {
|
|
|
|
self.set_viewport(size_info);
|
|
|
|
match &self.text_renderer {
|
|
|
|
TextRendererProvider::Gles2(renderer) => renderer.resize(size_info),
|
|
|
|
TextRendererProvider::Glsl3(renderer) => renderer.resize(size_info),
|
2021-02-19 19:00:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|