mirror of
https://github.com/storytold/craft-anything.git
synced 2026-11-05 20:47:45 +01:00
The window draws in a Windows VM instead of staying black (#38)
In a VMware Windows VM the virtual GPU is reached through GL, which drew a black window, while Windows' software renderer (WARP, over DX12) works. The desktop app now picks its graphics adapter itself on Windows: GL comes after every other adapter, WARP included, and otherwise the fastest device first, as before. GL stays the last resort when it's all there is, WGPU_BACKEND still narrows the choice, and the adapter used is written to desktop.log. Fixes #27
This commit is contained in:
@@ -42,7 +42,12 @@ fn main() -> eframe::Result {
|
||||
if let Ok(icon) = eframe::icon_data::from_png_bytes(craft_anything_ui_egui::APP_ICON_PNG) {
|
||||
viewport = viewport.with_icon(Arc::new(icon));
|
||||
}
|
||||
let options = eframe::NativeOptions { viewport, ..Default::default() };
|
||||
#[cfg_attr(not(windows), expect(unused_mut, reason = "only Windows picks its own graphics adapter"))]
|
||||
let mut options = eframe::NativeOptions { viewport, ..Default::default() };
|
||||
#[cfg(windows)]
|
||||
if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut options.wgpu_options.wgpu_setup {
|
||||
setup.native_adapter_selector = Some(Arc::new(pick_adapter));
|
||||
}
|
||||
let run = eframe::run_native(
|
||||
"Craft Anything",
|
||||
options,
|
||||
@@ -64,6 +69,55 @@ fn main() -> eframe::Result {
|
||||
run
|
||||
}
|
||||
|
||||
/// Windows: the adapter that draws the window. GL comes after every other one, Windows' own
|
||||
/// software renderer (WARP) included: in a VMware VM, GL is the way to the virtual GPU and draws a
|
||||
/// black window (#27). GL stays the last resort, and `WGPU_BACKEND` still narrows the choice.
|
||||
#[cfg(windows)]
|
||||
fn pick_adapter(adapters: &[eframe::wgpu::Adapter], surface: Option<&eframe::wgpu::Surface<'_>>) -> Result<eframe::wgpu::Adapter, String> {
|
||||
let picked = adapters.iter().filter(|a| surface.is_none_or(|s| a.is_surface_supported(s))).min_by_key(|a| {
|
||||
let info = a.get_info();
|
||||
adapter_rank(info.backend, info.device_type)
|
||||
});
|
||||
match picked {
|
||||
Some(a) => {
|
||||
log::info!("drawing with {:?}", a.get_info());
|
||||
Ok(a.clone())
|
||||
}
|
||||
None => Err(format!("None of the {} graphics adapters found can draw this window.", adapters.len())),
|
||||
}
|
||||
}
|
||||
|
||||
/// Lower is better: GL last, then the fastest kind of device first (wgpu's own high-performance
|
||||
/// preference).
|
||||
#[cfg(windows)]
|
||||
fn adapter_rank(backend: eframe::wgpu::Backend, device: eframe::wgpu::DeviceType) -> (bool, u8) {
|
||||
use eframe::wgpu::DeviceType;
|
||||
let speed = match device {
|
||||
DeviceType::DiscreteGpu => 0,
|
||||
DeviceType::IntegratedGpu => 1,
|
||||
DeviceType::VirtualGpu => 2,
|
||||
DeviceType::Cpu => 3,
|
||||
DeviceType::Other => 4,
|
||||
};
|
||||
(backend == eframe::wgpu::Backend::Gl, speed)
|
||||
}
|
||||
|
||||
#[cfg(all(test, windows))]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use eframe::wgpu::{Backend as B, DeviceType as T};
|
||||
|
||||
/// #27: a VMware VM offers its virtual GPU over GL and WARP over DX12; GL drew a black window.
|
||||
#[test]
|
||||
fn gl_comes_after_warp_and_every_gpu() {
|
||||
let best = |c: &[(B, T)]| c.iter().enumerate().min_by_key(|(_, (b, t))| adapter_rank(*b, *t)).map(|(i, _)| i);
|
||||
assert_eq!(best(&[(B::Gl, T::Other), (B::Dx12, T::Cpu)]), Some(1), "VMware: WARP, not GL");
|
||||
assert_eq!(best(&[(B::Gl, T::IntegratedGpu), (B::Dx12, T::Cpu)]), Some(1));
|
||||
assert_eq!(best(&[(B::Dx12, T::IntegratedGpu), (B::Vulkan, T::DiscreteGpu), (B::Dx12, T::Cpu)]), Some(1), "fastest GPU first");
|
||||
assert_eq!(best(&[(B::Gl, T::Other)]), Some(0), "GL when it's all there is");
|
||||
}
|
||||
}
|
||||
|
||||
/// Kept small: started afresh once it passes this size.
|
||||
const LOG_MAX: u64 = 512 * 1024;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user