diff --git a/Cargo.toml b/Cargo.toml index eac9006f7..86c835baf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ default-run = "wezterm" [build-dependencies] vergen = "3" +anyhow = "1.0" [target.'cfg(windows)'.build-dependencies] embed-resource = "1.3" diff --git a/assets/windows/mesa/README.md b/assets/windows/mesa/README.md new file mode 100644 index 000000000..675ca7349 --- /dev/null +++ b/assets/windows/mesa/README.md @@ -0,0 +1,6 @@ +This is a pre-built opendl32.dll for 64-bit Windows systems. +It was obtained from + +Mesa's License text can be found here: +https://docs.mesa3d.org/license.html +(a mixture of largely MITish licenses) diff --git a/assets/windows/mesa/opengl32.dll b/assets/windows/mesa/opengl32.dll new file mode 100644 index 000000000..61cc5cf65 Binary files /dev/null and b/assets/windows/mesa/opengl32.dll differ diff --git a/build.rs b/build.rs index 40d02a353..baf98fbc9 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,4 @@ +use anyhow::Context as _; use std::path::Path; use vergen::{generate_cargo_keys, ConstantsFlags}; @@ -81,7 +82,29 @@ fn main() { let src_name = conhost_dir.join(name); if !dest_name.exists() { - std::fs::copy(src_name, dest_name).unwrap(); + std::fs::copy(&src_name, &dest_name) + .context(format!( + "copy {} -> {}", + src_name.display(), + dest_name.display() + )) + .unwrap(); + } + } + + { + let dest_mesa = exe_output_dir.join("mesa"); + let _ = std::fs::create_dir(&dest_mesa); + let dest_name = dest_mesa.join("opengl32.dll"); + let src_name = windows_dir.join("mesa").join("opengl32.dll"); + if !dest_name.exists() { + std::fs::copy(&src_name, &dest_name) + .context(format!( + "copy {} -> {}", + src_name.display(), + dest_name.display() + )) + .unwrap(); } } diff --git a/ci/deploy.sh b/ci/deploy.sh index 7eb7dc8dd..fe740b495 100755 --- a/ci/deploy.sh +++ b/ci/deploy.sh @@ -52,6 +52,9 @@ case $OSTYPE in assets/windows/conhost/conpty.dll \ assets/windows/conhost/OpenConsole.exe \ $zipdir + mkdir $zipdir/mesa + cp $TARGET_DIR/release/mesa/opengl32.dll \ + $zipdir/mesa 7z a -tzip $zipname $zipdir iscc.exe -DMyAppVersion=${TAG_NAME#nightly} -F${instname} ci/windows-installer.iss ;; diff --git a/ci/windows-installer.iss b/ci/windows-installer.iss index 5e88d8184..178addb76 100644 --- a/ci/windows-installer.iss +++ b/ci/windows-installer.iss @@ -43,6 +43,7 @@ Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{ [Files] Source: "..\target\release\wezterm.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\target\release\mesa\opengl32.dll"; DestDir: "{app}\mesa"; Flags: ignoreversion Source: "..\target\release\conpty.dll"; DestDir: "{app}"; Flags: ignoreversion Source: "..\target\release\OpenConsole.exe"; DestDir: "{app}"; Flags: ignoreversion Source: "..\target\release\strip-ansi-escapes.exe"; DestDir: "{app}"; Flags: ignoreversion diff --git a/src/frontend/gui/mod.rs b/src/frontend/gui/mod.rs index fd4cc849a..046887e28 100644 --- a/src/frontend/gui/mod.rs +++ b/src/frontend/gui/mod.rs @@ -42,6 +42,11 @@ impl GuiFrontEnd { Self::try_new() } + pub fn try_new_swrast() -> anyhow::Result> { + ::window::prefer_swrast(); + Self::try_new() + } + pub fn try_new() -> anyhow::Result> { #[cfg(all(unix, not(target_os = "macos")))] { @@ -49,6 +54,7 @@ impl GuiFrontEnd { Connection::disable_wayland(); } } + let connection = Connection::init()?; let front_end = Rc::new(GuiFrontEnd { connection }); Ok(front_end) diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index ef723c1c0..2b3754bb1 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -16,6 +16,7 @@ pub mod muxserver; pub enum FrontEndSelection { OpenGL, Software, + OldSoftware, MuxServer, Null, } @@ -59,7 +60,8 @@ impl FrontEndSelection { let (front_end, is_gui) = match self { FrontEndSelection::MuxServer => (muxserver::MuxServerFrontEnd::try_new(), false), FrontEndSelection::Null => (muxserver::MuxServerFrontEnd::new_null(), false), - FrontEndSelection::Software => (gui::GuiFrontEnd::try_new_no_opengl(), true), + FrontEndSelection::Software => (gui::GuiFrontEnd::try_new_swrast(), true), + FrontEndSelection::OldSoftware => (gui::GuiFrontEnd::try_new_no_opengl(), true), FrontEndSelection::OpenGL => (gui::GuiFrontEnd::try_new(), true), }; @@ -73,7 +75,7 @@ impl FrontEndSelection { // TODO: find or build a proc macro for this pub fn variants() -> Vec<&'static str> { - vec!["OpenGL", "Software", "MuxServer", "Null"] + vec!["OpenGL", "Software", "OldSoftware", "MuxServer", "Null"] } } @@ -84,6 +86,7 @@ impl std::str::FromStr for FrontEndSelection { "muxserver" => Ok(FrontEndSelection::MuxServer), "null" => Ok(FrontEndSelection::Null), "software" => Ok(FrontEndSelection::Software), + "oldsoftware" => Ok(FrontEndSelection::OldSoftware), "opengl" => Ok(FrontEndSelection::OpenGL), _ => Err(anyhow!( "{} is not a valid FrontEndSelection variant, possible values are {:?}", diff --git a/window/src/lib.rs b/window/src/lib.rs index 4d8376417..b48cfe812 100644 --- a/window/src/lib.rs +++ b/window/src/lib.rs @@ -1,5 +1,6 @@ use promise::Future; use std::any::Any; +use std::sync::atomic::{AtomicBool, Ordering}; pub mod bitmaps; pub mod color; pub mod connection; @@ -292,3 +293,13 @@ pub trait WindowOpsMut { /// and/or in the task manager/task switcher fn set_icon(&mut self, _image: &dyn BitmapImage) {} } + +static PREFER_SWRAST: AtomicBool = AtomicBool::new(false); + +pub fn prefer_swrast() { + PREFER_SWRAST.store(true, Ordering::Release); +} + +pub fn is_swrast_preferred() -> bool { + PREFER_SWRAST.load(Ordering::Acquire) +} diff --git a/window/src/os/windows/wgl.rs b/window/src/os/windows/wgl.rs index 74eb8a0a2..69fa4ba8a 100644 --- a/window/src/os/windows/wgl.rs +++ b/window/src/os/windows/wgl.rs @@ -1,6 +1,7 @@ #![cfg(feature = "opengl")] use super::*; +use crate::is_swrast_preferred; use glium::backend::Backend; use std::ffi::CStr; use std::io::Error as IoError; @@ -8,6 +9,7 @@ use std::os::raw::c_void; use std::ptr::{null, null_mut}; use winapi::shared::windef::*; use winapi::um::libloaderapi::GetModuleHandleW; +use winapi::um::libloaderapi::*; use winapi::um::wingdi::*; use winapi::um::winuser::*; @@ -94,8 +96,25 @@ impl WglWrapper { } fn create() -> anyhow::Result { - let lib = libloading::Library::new("opengl32.dll")?; - log::trace!("loading opengl32.dll as {:?}", lib); + if is_swrast_preferred() { + let mesa_dir = std::env::current_exe() + .unwrap() + .parent() + .unwrap() + .join("mesa"); + let mesa_dir = wide_string(mesa_dir.to_str().unwrap()); + + unsafe { + AddDllDirectory(mesa_dir.as_ptr()); + SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + } + } + + let lib = libloading::Library::new("opengl32.dll").map_err(|e| { + log::error!("{:?}", e); + e + })?; + log::trace!("loaded {:?}", lib); let get_proc_address: libloading::Symbol = unsafe { lib.get(b"wglGetProcAddress\0")? };