add wgpu renderer for windows (#44)

This commit is contained in:
Scar-00
2026-06-24 19:10:56 -04:00
committed by GitHub
parent c17b4367d5
commit ce08af96db
8 changed files with 231 additions and 57 deletions
+1
View File
@@ -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
+6 -1
View File
@@ -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(),
+2
View File
@@ -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
+48 -22
View File
@@ -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,
+8
View File
@@ -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::*;
+51 -13
View File
@@ -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,
+6 -5
View File
@@ -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>,
+109 -16
View File
@@ -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()
}