diff options
Diffstat (limited to 'alacritty/src/renderer')
-rw-r--r-- | alacritty/src/renderer/mod.rs | 21 | ||||
-rw-r--r-- | alacritty/src/renderer/platform.rs | 116 |
2 files changed, 135 insertions, 2 deletions
diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs index 6ee8815c..d8c6fb6d 100644 --- a/alacritty/src/renderer/mod.rs +++ b/alacritty/src/renderer/mod.rs @@ -1,8 +1,11 @@ use std::collections::HashSet; -use std::ffi::CStr; +use std::ffi::{CStr, CString}; use std::fmt; +use std::sync::atomic::{AtomicBool, Ordering}; use crossfont::Metrics; +use glutin::context::PossiblyCurrentContext; +use glutin::display::{GetGlDisplay, GlDisplay}; use log::info; use once_cell::sync::OnceCell; @@ -16,6 +19,7 @@ use crate::gl; use crate::renderer::rects::{RectRenderer, RenderRect}; use crate::renderer::shader::ShaderError; +pub mod platform; pub mod rects; mod shader; mod text; @@ -33,6 +37,9 @@ macro_rules! cstr { } pub(crate) use cstr; +/// Whether the OpenGL functions have been loaded. +pub static GL_FUNS_LOADED: AtomicBool = AtomicBool::new(false); + #[derive(Debug)] pub enum Error { /// Shader error. @@ -80,7 +87,17 @@ impl Renderer { /// /// This will automatically pick between the GLES2 and GLSL3 renderer based on the GPU's /// supported OpenGL version. - pub fn new() -> Result<Self, Error> { + pub fn new(context: &PossiblyCurrentContext) -> Result<Self, Error> { + // We need to load OpenGL functions once per instance, but only after we make our context + // current due to WGL limitations. + if !GL_FUNS_LOADED.swap(true, Ordering::Relaxed) { + let gl_display = context.display(); + gl::load_with(|symbol| { + let symbol = CString::new(symbol).unwrap(); + gl_display.get_proc_address(symbol.as_c_str()).cast() + }); + } + 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 _); diff --git a/alacritty/src/renderer/platform.rs b/alacritty/src/renderer/platform.rs new file mode 100644 index 00000000..0f55d941 --- /dev/null +++ b/alacritty/src/renderer/platform.rs @@ -0,0 +1,116 @@ +//! The graphics platform that is used by the renderer. + +use std::num::NonZeroU32; + +use glutin::config::{ColorBufferType, Config, ConfigTemplateBuilder, GetGlConfig}; +use glutin::context::{ + ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentContext, Version, +}; +use glutin::display::{Display, DisplayApiPreference, GetGlDisplay}; +use glutin::error::Result as GlutinResult; +use glutin::prelude::*; +use glutin::surface::{Surface, SurfaceAttributesBuilder, WindowSurface}; + +use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; +use winit::dpi::PhysicalSize; +#[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] +use winit::platform::unix; + +/// Create the GL display. +pub fn create_gl_display( + raw_display_handle: RawDisplayHandle, + _raw_window_handle: Option<RawWindowHandle>, +) -> GlutinResult<Display> { + #[cfg(target_os = "macos")] + let preference = DisplayApiPreference::Cgl; + + #[cfg(windows)] + let preference = DisplayApiPreference::Wgl(Some(_raw_window_handle.unwrap())); + + #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] + let preference = DisplayApiPreference::GlxThenEgl(Box::new(unix::register_xlib_error_hook)); + + #[cfg(all(not(feature = "x11"), not(any(target_os = "macos", windows))))] + let preference = DisplayApiPreference::Egl; + + let display = unsafe { Display::new(raw_display_handle, preference)? }; + log::info!("Using {}", { display.version_string() }); + Ok(display) +} + +pub fn pick_gl_config( + gl_display: &Display, + raw_window_handle: Option<RawWindowHandle>, +) -> Result<Config, String> { + let mut default_config = ConfigTemplateBuilder::new().with_transparency(true); + + if let Some(raw_window_handle) = raw_window_handle { + default_config = default_config.compatible_with_native_window(raw_window_handle); + } + + let config_10bit = default_config + .clone() + .with_buffer_type(ColorBufferType::Rgb { r_size: 10, g_size: 10, b_size: 10 }) + .with_alpha_size(2); + + let configs = [ + default_config.clone(), + config_10bit.clone(), + default_config.with_transparency(false), + config_10bit.with_transparency(false), + ]; + + for config in configs { + let gl_config = unsafe { + gl_display.find_configs(config.build()).ok().and_then(|mut configs| configs.next()) + }; + + if let Some(gl_config) = gl_config { + return Ok(gl_config); + } + } + + Err(String::from("failed to find suitable GL configuration.")) +} + +pub fn create_gl_context( + gl_display: &Display, + gl_config: &Config, + raw_window_handle: Option<RawWindowHandle>, +) -> GlutinResult<NotCurrentContext> { + let context_attributes = ContextAttributesBuilder::new() + .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3)))) + .build(raw_window_handle); + + unsafe { + if let Ok(gl_context) = gl_display.create_context(gl_config, &context_attributes) { + Ok(gl_context) + } else { + let context_attributes = ContextAttributesBuilder::new() + .with_profile(GlProfile::Compatibility) + .with_context_api(ContextApi::OpenGl(Some(Version::new(2, 1)))) + .build(raw_window_handle); + gl_display.create_context(gl_config, &context_attributes) + } + } +} + +pub fn create_gl_surface( + gl_context: &NotCurrentContext, + size: PhysicalSize<u32>, + raw_window_handle: RawWindowHandle, +) -> GlutinResult<Surface<WindowSurface>> { + // Get the display and the config used to create that context. + let gl_display = gl_context.display(); + let gl_config = gl_context.config(); + + let surface_attributes = + SurfaceAttributesBuilder::<WindowSurface>::new().with_srgb(Some(false)).build( + raw_window_handle, + NonZeroU32::new(size.width).unwrap(), + NonZeroU32::new(size.height).unwrap(), + ); + + // Create the GL surface to draw into. + unsafe { gl_display.create_window_surface(&gl_config, &surface_attributes) } +} |