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")? };