add wgpu renderer for windows (#44)
This commit is contained in:
@@ -24,6 +24,7 @@ screen-capture = [
|
||||
runtime_shaders = ["gpui_macos/runtime_shaders"]
|
||||
wayland = ["gpui_linux/wayland"]
|
||||
x11 = ["gpui_linux/x11"]
|
||||
wgpu = ["gpui_windows/wgpu"]
|
||||
|
||||
[dependencies]
|
||||
gpui.workspace = true
|
||||
|
||||
@@ -209,8 +209,13 @@ impl WgpuContext {
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub fn instance(display: Box<dyn wgpu::wgt::WgpuHasDisplayHandle>) -> wgpu::Instance {
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let backends = wgpu::Backends::VULKAN | wgpu::Backends::GL;
|
||||
#[cfg(target_os = "windows")]
|
||||
let backends = wgpu::Backends::DX12;
|
||||
|
||||
wgpu::Instance::new(wgpu::InstanceDescriptor {
|
||||
backends: wgpu::Backends::VULKAN | wgpu::Backends::GL,
|
||||
backends,
|
||||
flags: wgpu::InstanceFlags::default(),
|
||||
backend_options: wgpu::BackendOptions::default(),
|
||||
memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),
|
||||
|
||||
@@ -15,9 +15,11 @@ path = "src/gpui_windows.rs"
|
||||
default = ["gpui/default"]
|
||||
test-support = ["gpui/test-support"]
|
||||
screen-capture = ["gpui/screen-capture", "scap"]
|
||||
wgpu = ["dep:gpui_wgpu"]
|
||||
|
||||
[dependencies]
|
||||
gpui.workspace = true
|
||||
gpui_wgpu = { workspace = true, optional = true, features = ["font-kit"] }
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
accesskit.workspace = true
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::{rc::Rc, sync::atomic::Ordering};
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
use crate::window::RawWindow;
|
||||
use ::util::ResultExt;
|
||||
use anyhow::Context as _;
|
||||
use std::{rc::Rc, sync::atomic::Ordering};
|
||||
use windows::{
|
||||
Win32::{
|
||||
Foundation::*,
|
||||
@@ -209,13 +210,25 @@ impl WindowsWindowInner {
|
||||
let new_logical_size = device_size.to_pixels(scale_factor);
|
||||
|
||||
self.state.logical_size.set(new_logical_size);
|
||||
if should_resize_renderer
|
||||
&& let Err(e) = self.state.renderer.borrow_mut().resize(device_size)
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
{
|
||||
log::error!("Failed to resize renderer, invalidating devices: {}", e);
|
||||
self.state
|
||||
.invalidate_devices
|
||||
.store(true, std::sync::atomic::Ordering::Release);
|
||||
if should_resize_renderer
|
||||
&& let Err(e) = self.state.renderer.borrow_mut().resize(device_size)
|
||||
{
|
||||
log::error!("Failed to resize renderer, invalidating devices: {}", e);
|
||||
self.state
|
||||
.invalidate_devices
|
||||
.store(true, std::sync::atomic::Ordering::Release);
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
{
|
||||
if should_resize_renderer {
|
||||
self.state
|
||||
.renderer
|
||||
.borrow_mut()
|
||||
.update_drawable_size(device_size)
|
||||
}
|
||||
}
|
||||
if let Some(mut callback) = self.state.callbacks.resize.take() {
|
||||
callback(new_logical_size, scale_factor);
|
||||
@@ -1193,15 +1206,27 @@ impl WindowsWindowInner {
|
||||
}
|
||||
|
||||
fn handle_device_lost(&self, lparam: LPARAM) -> Option<isize> {
|
||||
let devices = lparam.0 as *const DirectXDevices;
|
||||
let devices = unsafe { &*devices };
|
||||
if let Err(err) = self
|
||||
.state
|
||||
.renderer
|
||||
.borrow_mut()
|
||||
.handle_device_lost(&devices)
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
{
|
||||
panic!("Device lost: {err}");
|
||||
let devices = lparam.0 as *const DirectXDevices;
|
||||
let devices = unsafe { &*devices };
|
||||
if let Err(err) = self
|
||||
.state
|
||||
.renderer
|
||||
.borrow_mut()
|
||||
.handle_device_lost(&devices)
|
||||
{
|
||||
panic!("Device lost: {err}");
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "wgpu")]
|
||||
{
|
||||
_ = lparam;
|
||||
if let Err(err) = self.state.renderer.borrow_mut().recover(&RawWindow {
|
||||
hwnd: self.platform_window_handle,
|
||||
}) {
|
||||
panic!("Device lost: {err}");
|
||||
}
|
||||
}
|
||||
// Make sure the first `draw_window` after recovery (whether it comes
|
||||
// from the forced WM_GPUI_FORCE_UPDATE_WINDOW or a stray WM_PAINT in
|
||||
@@ -1219,7 +1244,6 @@ impl WindowsWindowInner {
|
||||
#[inline]
|
||||
fn draw_window(&self, handle: HWND, force_render: bool) -> Option<isize> {
|
||||
let mut request_frame = self.state.callbacks.request_frame.take()?;
|
||||
|
||||
self.state.direct_manipulation.update();
|
||||
|
||||
let events = self.state.direct_manipulation.drain_events();
|
||||
@@ -1231,12 +1255,14 @@ impl WindowsWindowInner {
|
||||
self.state.callbacks.input.set(Some(func));
|
||||
}
|
||||
}
|
||||
|
||||
let force_render = force_render || self.state.force_render_after_recovery.take();
|
||||
if force_render {
|
||||
// Re-enable drawing after a device loss recovery. The forced render
|
||||
// will rebuild the scene with fresh atlas textures.
|
||||
self.state.renderer.borrow_mut().mark_drawable();
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
{
|
||||
if force_render {
|
||||
// Re-enable drawing after a device loss recovery. The forced render
|
||||
// will rebuild the scene with fresh atlas textures.
|
||||
self.state.renderer.borrow_mut().mark_drawable();
|
||||
}
|
||||
}
|
||||
request_frame(RequestFrameOptions {
|
||||
require_presentation: false,
|
||||
|
||||
@@ -3,9 +3,13 @@
|
||||
mod clipboard;
|
||||
mod destination_list;
|
||||
mod direct_manipulation;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
mod direct_write;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
mod directx_atlas;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
mod directx_devices;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
mod directx_renderer;
|
||||
mod dispatcher;
|
||||
mod display;
|
||||
@@ -20,9 +24,13 @@ mod wrapper;
|
||||
|
||||
pub(crate) use clipboard::*;
|
||||
pub(crate) use destination_list::*;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub(crate) use direct_write::*;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub(crate) use directx_atlas::*;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub(crate) use directx_devices::*;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub(crate) use directx_renderer::*;
|
||||
pub(crate) use dispatcher::*;
|
||||
pub(crate) use display::*;
|
||||
|
||||
@@ -15,11 +15,13 @@ use futures::channel::oneshot::{self, Receiver};
|
||||
use itertools::Itertools;
|
||||
use parking_lot::RwLock;
|
||||
use smallvec::SmallVec;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
use windows::Win32::Graphics::Direct3D11::ID3D11Device;
|
||||
use windows::{
|
||||
UI::ViewManagement::UISettings,
|
||||
Win32::{
|
||||
Foundation::*,
|
||||
Graphics::{Direct3D11::ID3D11Device, Gdi::*},
|
||||
Graphics::Gdi::*,
|
||||
Security::Credentials::*,
|
||||
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*},
|
||||
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
|
||||
@@ -39,6 +41,7 @@ pub struct WindowsPlatform {
|
||||
background_executor: BackgroundExecutor,
|
||||
foreground_executor: ForegroundExecutor,
|
||||
text_system: Arc<dyn PlatformTextSystem>,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
direct_write_text_system: Option<Arc<DirectWriteTextSystem>>,
|
||||
drop_target_helper: Option<IDropTargetHelper>,
|
||||
/// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices
|
||||
@@ -65,6 +68,7 @@ pub(crate) struct WindowsPlatformState {
|
||||
pub(crate) current_cursor: Cell<Option<HCURSOR>>,
|
||||
/// Shared with each window so `WM_SETCURSOR` can read it directly.
|
||||
pub(crate) cursor_visible: Arc<AtomicBool>,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices: RefCell<Option<DirectXDevices>>,
|
||||
}
|
||||
|
||||
@@ -80,7 +84,7 @@ struct PlatformCallbacks {
|
||||
}
|
||||
|
||||
impl WindowsPlatformState {
|
||||
fn new(directx_devices: Option<DirectXDevices>) -> Self {
|
||||
fn new(#[cfg(not(feature = "wgpu"))] directx_devices: Option<DirectXDevices>) -> Self {
|
||||
let callbacks = PlatformCallbacks::default();
|
||||
let jump_list = JumpList::new();
|
||||
let current_cursor = load_cursor(CursorStyle::Arrow);
|
||||
@@ -90,6 +94,7 @@ impl WindowsPlatformState {
|
||||
jump_list: RefCell::new(jump_list),
|
||||
current_cursor: Cell::new(current_cursor),
|
||||
cursor_visible: Arc::new(AtomicBool::new(true)),
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices: RefCell::new(directx_devices),
|
||||
menus: RefCell::new(Vec::new()),
|
||||
}
|
||||
@@ -101,6 +106,7 @@ impl WindowsPlatform {
|
||||
unsafe {
|
||||
OleInitialize(None).context("unable to initialize Windows OLE")?;
|
||||
}
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let (directx_devices, text_system, direct_write_text_system) = if !headless {
|
||||
let devices = DirectXDevices::new().context("Creating DirectX devices")?;
|
||||
let dw_text_system = Arc::new(
|
||||
@@ -119,6 +125,9 @@ impl WindowsPlatform {
|
||||
None,
|
||||
)
|
||||
};
|
||||
#[cfg(feature = "wgpu")]
|
||||
let text_system =
|
||||
Arc::new(gpui_wgpu::CosmicTextSystem::new("Segoe UI")) as Arc<dyn PlatformTextSystem>;
|
||||
|
||||
let (main_sender, main_receiver) = PriorityQueueReceiver::new();
|
||||
let validation_number = if usize::BITS == 64 {
|
||||
@@ -135,6 +144,7 @@ impl WindowsPlatform {
|
||||
validation_number,
|
||||
main_sender: Some(main_sender),
|
||||
main_receiver: Some(main_receiver),
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices,
|
||||
dispatcher: None,
|
||||
};
|
||||
@@ -164,6 +174,9 @@ impl WindowsPlatform {
|
||||
.context("CreateWindowExW did not run correctly")?;
|
||||
let handle = result?;
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
let disable_direct_composition = true;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION)
|
||||
.is_ok_and(|value| value == "true" || value == "1");
|
||||
let background_executor = BackgroundExecutor::new(dispatcher.clone());
|
||||
@@ -192,6 +205,7 @@ impl WindowsPlatform {
|
||||
background_executor,
|
||||
foreground_executor,
|
||||
text_system,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
direct_write_text_system,
|
||||
disable_direct_composition,
|
||||
drop_target_helper,
|
||||
@@ -228,6 +242,7 @@ impl WindowsPlatform {
|
||||
main_receiver: self.inner.main_receiver.clone(),
|
||||
platform_window_handle: self.handle,
|
||||
disable_direct_composition: self.disable_direct_composition,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices: self.inner.state.directx_devices.borrow().clone().unwrap(),
|
||||
invalidate_devices: self.invalidate_devices.clone(),
|
||||
}
|
||||
@@ -295,17 +310,24 @@ impl WindowsPlatform {
|
||||
}
|
||||
|
||||
fn begin_vsync_thread(&self) {
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let Some(directx_devices) = self.inner.state.directx_devices.borrow().clone() else {
|
||||
return;
|
||||
};
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let Some(direct_write_text_system) = &self.direct_write_text_system else {
|
||||
return;
|
||||
};
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let mut directx_device = directx_devices;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let platform_window: SafeHwnd = self.handle.into();
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let validation_number = self.inner.validation_number;
|
||||
let all_windows = Arc::downgrade(&self.raw_window_handles);
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let text_system = Arc::downgrade(direct_write_text_system);
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let invalidate_devices = self.invalidate_devices.clone();
|
||||
|
||||
std::thread::Builder::new()
|
||||
@@ -314,17 +336,20 @@ impl WindowsPlatform {
|
||||
let vsync_provider = VSyncProvider::new();
|
||||
loop {
|
||||
vsync_provider.wait_for_vsync();
|
||||
if check_device_lost(&directx_device.device)
|
||||
|| invalidate_devices.fetch_and(false, Ordering::Acquire)
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
{
|
||||
if let Err(err) = handle_gpu_device_lost(
|
||||
&mut directx_device,
|
||||
platform_window.as_raw(),
|
||||
validation_number,
|
||||
&all_windows,
|
||||
&text_system,
|
||||
) {
|
||||
panic!("Device lost: {err}");
|
||||
if check_device_lost(&directx_device.device)
|
||||
|| invalidate_devices.fetch_and(false, Ordering::Acquire)
|
||||
{
|
||||
if let Err(err) = handle_gpu_device_lost(
|
||||
&mut directx_device,
|
||||
platform_window.as_raw(),
|
||||
validation_number,
|
||||
&all_windows,
|
||||
&text_system,
|
||||
) {
|
||||
panic!("Device lost: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
let Some(all_windows) = all_windows.upgrade() else {
|
||||
@@ -840,7 +865,10 @@ impl Platform for WindowsPlatform {
|
||||
|
||||
impl WindowsPlatformInner {
|
||||
fn new(context: &mut PlatformWindowCreateContext) -> Result<Rc<Self>> {
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let state = WindowsPlatformState::new(context.directx_devices.take());
|
||||
#[cfg(feature = "wgpu")]
|
||||
let state = WindowsPlatformState::new();
|
||||
Ok(Rc::new(Self {
|
||||
state,
|
||||
raw_window_handles: context.raw_window_handles.clone(),
|
||||
@@ -905,7 +933,12 @@ impl WindowsPlatformInner {
|
||||
WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD => self.run_foreground_task(),
|
||||
WM_GPUI_DOCK_MENU_ACTION => self.handle_dock_action_event(lparam.0 as _),
|
||||
WM_GPUI_KEYBOARD_LAYOUT_CHANGED => self.handle_keyboard_layout_change(),
|
||||
WM_GPUI_GPU_DEVICE_LOST => self.handle_device_lost(lparam),
|
||||
WM_GPUI_GPU_DEVICE_LOST => {
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
return self.handle_device_lost(lparam);
|
||||
#[cfg(feature = "wgpu")]
|
||||
Some(0)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -1019,6 +1052,7 @@ impl WindowsPlatformInner {
|
||||
Some(0)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
fn handle_device_lost(&self, lparam: LPARAM) -> Option<isize> {
|
||||
let directx_devices = lparam.0 as *const DirectXDevices;
|
||||
let directx_devices = unsafe { &*directx_devices };
|
||||
@@ -1050,6 +1084,7 @@ pub(crate) struct WindowCreationInfo {
|
||||
pub(crate) main_receiver: PriorityQueueReceiver<RunnableVariant>,
|
||||
pub(crate) platform_window_handle: HWND,
|
||||
pub(crate) disable_direct_composition: bool,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub(crate) directx_devices: DirectXDevices,
|
||||
/// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices
|
||||
/// as resizing them has failed, causing us to have lost at least the render target.
|
||||
@@ -1062,6 +1097,7 @@ struct PlatformWindowCreateContext {
|
||||
validation_number: usize,
|
||||
main_sender: Option<PriorityQueueSender<RunnableVariant>>,
|
||||
main_receiver: Option<PriorityQueueReceiver<RunnableVariant>>,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices: Option<DirectXDevices>,
|
||||
dispatcher: Option<Arc<WindowsDispatcher>>,
|
||||
}
|
||||
@@ -1249,6 +1285,7 @@ fn should_auto_hide_scrollbars() -> Result<bool> {
|
||||
Ok(ui_settings.AutoHideScrollBars()?)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
fn check_device_lost(device: &ID3D11Device) -> bool {
|
||||
let device_state = unsafe { device.GetDeviceRemovedReason() };
|
||||
match device_state {
|
||||
@@ -1260,6 +1297,7 @@ fn check_device_lost(device: &ID3D11Device) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
fn handle_gpu_device_lost(
|
||||
directx_devices: &mut DirectXDevices,
|
||||
platform_window: HWND,
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use ::util::ResultExt;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
use anyhow::Context;
|
||||
use windows::{
|
||||
UI::{
|
||||
Color,
|
||||
ViewManagement::{UIColorType, UISettings},
|
||||
},
|
||||
Win32::{
|
||||
Foundation::*, Graphics::Dwm::*, System::LibraryLoader::LoadLibraryA,
|
||||
UI::WindowsAndMessaging::*,
|
||||
},
|
||||
core::{BOOL, PCSTR},
|
||||
Win32::{Foundation::*, Graphics::Dwm::*, UI::WindowsAndMessaging::*},
|
||||
core::BOOL,
|
||||
};
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
use windows::{Win32::System::LibraryLoader::LoadLibraryA, core::PCSTR};
|
||||
|
||||
use crate::*;
|
||||
use gpui::*;
|
||||
@@ -174,6 +174,7 @@ fn is_color_light(color: &Color) -> bool {
|
||||
((5 * color.G as u32) + (2 * color.R as u32) + color.B as u32) > (8 * 128)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub(crate) fn with_dll_library<R, F>(dll_name: PCSTR, f: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(HMODULE) -> Result<R>,
|
||||
|
||||
@@ -32,6 +32,9 @@ use crate::direct_manipulation::DirectManipulationHandler;
|
||||
use crate::*;
|
||||
use gpui::*;
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
use gpui_wgpu::{WgpuRenderer, WgpuSurfaceConfig, wgpu};
|
||||
|
||||
pub(crate) struct WindowsWindow(pub Rc<WindowsWindowInner>);
|
||||
|
||||
impl std::ops::Deref for WindowsWindow {
|
||||
@@ -62,6 +65,9 @@ pub struct WindowsWindowState {
|
||||
pub hovered: Cell<bool>,
|
||||
pub direct_manipulation: DirectManipulationHandler,
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
pub renderer: RefCell<WgpuRenderer>,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub renderer: RefCell<DirectXRenderer>,
|
||||
/// Set after a GPU device-lost recovery so the next `draw_window` call is
|
||||
/// treated as a forced render. This guarantees the next frame both
|
||||
@@ -79,6 +85,7 @@ pub struct WindowsWindowState {
|
||||
pub display: Cell<WindowsDisplay>,
|
||||
/// Flag to instruct the `VSyncProvider` thread to invalidate the directx devices
|
||||
/// as resizing them has failed, causing us to have lost at least the render target.
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
pub invalidate_devices: Arc<AtomicBool>,
|
||||
fullscreen: Cell<Option<StyleAndBounds>>,
|
||||
initial_placement: Cell<Option<WindowOpenStatus>>,
|
||||
@@ -104,34 +111,45 @@ pub(crate) struct WindowsWindowInner {
|
||||
impl WindowsWindowState {
|
||||
fn new(
|
||||
hwnd: HWND,
|
||||
directx_devices: &DirectXDevices,
|
||||
#[cfg(not(feature = "wgpu"))] directx_devices: &DirectXDevices,
|
||||
window_params: &CREATESTRUCTW,
|
||||
current_cursor: Option<HCURSOR>,
|
||||
cursor_visible: Arc<AtomicBool>,
|
||||
display: WindowsDisplay,
|
||||
min_size: Option<Size<Pixels>>,
|
||||
appearance: WindowAppearance,
|
||||
disable_direct_composition: bool,
|
||||
invalidate_devices: Arc<AtomicBool>,
|
||||
#[cfg(not(feature = "wgpu"))] disable_direct_composition: bool,
|
||||
#[cfg(not(feature = "wgpu"))] invalidate_devices: Arc<AtomicBool>,
|
||||
) -> Result<Self> {
|
||||
let scale_factor = {
|
||||
let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
|
||||
monitor_dpi / USER_DEFAULT_SCREEN_DPI as f32
|
||||
};
|
||||
let origin = logical_point(window_params.x as f32, window_params.y as f32, scale_factor);
|
||||
let logical_size = {
|
||||
let physical_size = size(
|
||||
DevicePixels(window_params.cx),
|
||||
DevicePixels(window_params.cy),
|
||||
);
|
||||
physical_size.to_pixels(scale_factor)
|
||||
};
|
||||
let physical_size = size(
|
||||
DevicePixels(window_params.cx),
|
||||
DevicePixels(window_params.cy),
|
||||
);
|
||||
let logical_size = { physical_size.to_pixels(scale_factor) };
|
||||
let fullscreen_restore_bounds = Bounds {
|
||||
origin,
|
||||
size: logical_size,
|
||||
};
|
||||
let border_offset = WindowBorderOffset::default();
|
||||
let restore_from_minimized = None;
|
||||
#[cfg(feature = "wgpu")]
|
||||
let renderer = WgpuRenderer::new(
|
||||
Rc::new(RefCell::new(None)),
|
||||
&RawWindow { hwnd },
|
||||
WgpuSurfaceConfig {
|
||||
size: physical_size,
|
||||
transparent: false,
|
||||
preferred_present_mode: Some(wgpu::PresentMode::Mailbox),
|
||||
},
|
||||
None,
|
||||
)
|
||||
.context("Creating Wgpu renderer")?;
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
let renderer = DirectXRenderer::new(hwnd, directx_devices, disable_direct_composition)
|
||||
.context("Creating DirectX renderer")?;
|
||||
let callbacks = Callbacks::default();
|
||||
@@ -175,6 +193,7 @@ impl WindowsWindowState {
|
||||
fullscreen: Cell::new(fullscreen),
|
||||
initial_placement: Cell::new(initial_placement),
|
||||
hwnd,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
invalidate_devices,
|
||||
direct_manipulation,
|
||||
a11y: RefCell::new(None),
|
||||
@@ -244,6 +263,7 @@ impl WindowsWindowInner {
|
||||
fn new(context: &mut WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {
|
||||
let state = WindowsWindowState::new(
|
||||
hwnd,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
&context.directx_devices,
|
||||
cs,
|
||||
context.current_cursor,
|
||||
@@ -251,7 +271,9 @@ impl WindowsWindowInner {
|
||||
context.display,
|
||||
context.min_size,
|
||||
context.appearance,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
context.disable_direct_composition,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
context.invalidate_devices.clone(),
|
||||
)?;
|
||||
|
||||
@@ -393,8 +415,11 @@ struct WindowCreateContext {
|
||||
main_receiver: PriorityQueueReceiver<RunnableVariant>,
|
||||
platform_window_handle: HWND,
|
||||
appearance: WindowAppearance,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
disable_direct_composition: bool,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices: DirectXDevices,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
invalidate_devices: Arc<AtomicBool>,
|
||||
parent_hwnd: Option<HWND>,
|
||||
}
|
||||
@@ -415,9 +440,14 @@ impl WindowsWindow {
|
||||
main_receiver,
|
||||
platform_window_handle,
|
||||
disable_direct_composition,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices,
|
||||
invalidate_devices,
|
||||
} = creation_info;
|
||||
#[cfg(feature = "wgpu")]
|
||||
{
|
||||
_ = invalidate_devices;
|
||||
}
|
||||
register_window_class(icon);
|
||||
let parent_hwnd = if params.kind == WindowKind::Dialog {
|
||||
let parent_window = unsafe { GetActiveWindow() };
|
||||
@@ -496,8 +526,11 @@ impl WindowsWindow {
|
||||
main_receiver,
|
||||
platform_window_handle,
|
||||
appearance,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
disable_direct_composition,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
directx_devices,
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
invalidate_devices,
|
||||
parent_hwnd,
|
||||
};
|
||||
@@ -548,6 +581,35 @@ impl WindowsWindow {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct RawWindow {
|
||||
pub hwnd: HWND,
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
unsafe impl Send for RawWindow {}
|
||||
#[cfg(feature = "wgpu")]
|
||||
unsafe impl Sync for RawWindow {}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
impl rwh::HasWindowHandle for RawWindow {
|
||||
fn window_handle(&self) -> std::result::Result<rwh::WindowHandle<'_>, rwh::HandleError> {
|
||||
let raw = rwh::Win32WindowHandle::new(unsafe {
|
||||
NonZeroIsize::new_unchecked(self.hwnd.0 as isize)
|
||||
})
|
||||
.into();
|
||||
Ok(unsafe { rwh::WindowHandle::borrow_raw(raw) })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
impl rwh::HasDisplayHandle for RawWindow {
|
||||
fn display_handle(&self) -> std::result::Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
|
||||
Ok(rwh::DisplayHandle::windows())
|
||||
}
|
||||
}
|
||||
|
||||
impl rwh::HasWindowHandle for WindowsWindow {
|
||||
fn window_handle(&self) -> std::result::Result<rwh::WindowHandle<'_>, rwh::HandleError> {
|
||||
let raw = rwh::Win32WindowHandle::new(unsafe {
|
||||
@@ -951,15 +1013,43 @@ impl PlatformWindow for WindowsWindow {
|
||||
}
|
||||
|
||||
fn draw(&self, scene: &Scene) {
|
||||
self.state
|
||||
.renderer
|
||||
.borrow_mut()
|
||||
.draw(scene, self.state.background_appearance.get())
|
||||
.log_err();
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
{
|
||||
self.state
|
||||
.renderer
|
||||
.borrow_mut()
|
||||
.draw(scene, self.state.background_appearance.get())
|
||||
.log_err();
|
||||
}
|
||||
|
||||
#[cfg(feature = "wgpu")]
|
||||
{
|
||||
let mut renderer = self.state.renderer.borrow_mut();
|
||||
if renderer.device_lost() {
|
||||
match renderer.recover(&RawWindow {
|
||||
hwnd: self.platform_window_handle,
|
||||
}) {
|
||||
Ok(()) => {}
|
||||
Err(err) => {
|
||||
log::warn!("GPU recovery failed, will retry on next frame: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
self.state.force_render_after_recovery.set(true);
|
||||
return;
|
||||
}
|
||||
if !renderer.draw(scene) {
|
||||
log::error!("failed to render scene");
|
||||
}
|
||||
|
||||
if renderer.needs_redraw() {
|
||||
self.state.force_render_after_recovery.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||
self.state.renderer.borrow().sprite_atlas()
|
||||
self.state.renderer.borrow().sprite_atlas().clone()
|
||||
}
|
||||
|
||||
fn get_raw_handle(&self) -> HWND {
|
||||
@@ -967,6 +1057,9 @@ impl PlatformWindow for WindowsWindow {
|
||||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<GpuSpecs> {
|
||||
#[cfg(feature = "wgpu")]
|
||||
return Some(self.state.renderer.borrow().gpu_specs());
|
||||
#[cfg(not(feature = "wgpu"))]
|
||||
self.state.renderer.borrow().gpu_specs().log_err()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user