Compare commits
4 commits
main
...
windows/fp
Author | SHA1 | Date | |
---|---|---|---|
![]() |
dbba54d7f8 | ||
![]() |
fc5bcf0ad1 | ||
![]() |
87b4710dd0 | ||
![]() |
2261dcaa8e |
7 changed files with 147 additions and 30 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -12344,18 +12344,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "profiling"
|
name = "profiling"
|
||||||
version = "1.0.16"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
|
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"profiling-procmacros",
|
"profiling-procmacros",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "profiling-procmacros"
|
name = "profiling-procmacros"
|
||||||
version = "1.0.16"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
|
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.101",
|
"syn 2.0.101",
|
||||||
|
|
|
@ -537,7 +537,7 @@ portable-pty = "0.9.0"
|
||||||
postage = { version = "0.5", features = ["futures-traits"] }
|
postage = { version = "0.5", features = ["futures-traits"] }
|
||||||
pretty_assertions = { version = "1.3.0", features = ["unstable"] }
|
pretty_assertions = { version = "1.3.0", features = ["unstable"] }
|
||||||
proc-macro2 = "1.0.93"
|
proc-macro2 = "1.0.93"
|
||||||
profiling = "1"
|
profiling = "1.0.17"
|
||||||
prost = "0.9"
|
prost = "0.9"
|
||||||
prost-build = "0.9"
|
prost-build = "0.9"
|
||||||
prost-types = "0.9"
|
prost-types = "0.9"
|
||||||
|
|
|
@ -207,7 +207,7 @@ impl DirectXRenderer {
|
||||||
|
|
||||||
fn present(&mut self) -> Result<()> {
|
fn present(&mut self) -> Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let result = self.resources.swap_chain.Present(1, DXGI_PRESENT(0));
|
let result = self.resources.swap_chain.Present(0, DXGI_PRESENT(0));
|
||||||
// Presenting the swap chain can fail if the DirectX device was removed or reset.
|
// Presenting the swap chain can fail if the DirectX device was removed or reset.
|
||||||
if result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET {
|
if result == DXGI_ERROR_DEVICE_REMOVED || result == DXGI_ERROR_DEVICE_RESET {
|
||||||
let reason = self.devices.device.GetDeviceRemovedReason();
|
let reason = self.devices.device.GetDeviceRemovedReason();
|
||||||
|
@ -286,6 +286,7 @@ impl DirectXRenderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[profiling::function]
|
||||||
pub(crate) fn draw(&mut self, scene: &Scene) -> Result<()> {
|
pub(crate) fn draw(&mut self, scene: &Scene) -> Result<()> {
|
||||||
self.pre_draw()?;
|
self.pre_draw()?;
|
||||||
for batch in scene.batches() {
|
for batch in scene.batches() {
|
||||||
|
|
|
@ -238,6 +238,7 @@ fn handle_timer_msg(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[profiling::function]
|
||||||
fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
||||||
draw_window(handle, false, state_ptr)
|
draw_window(handle, false, state_ptr)
|
||||||
}
|
}
|
||||||
|
@ -373,6 +374,7 @@ fn handle_syskeyup_msg(
|
||||||
|
|
||||||
// It's a known bug that you can't trigger `ctrl-shift-0`. See:
|
// It's a known bug that you can't trigger `ctrl-shift-0`. See:
|
||||||
// https://superuser.com/questions/1455762/ctrl-shift-number-key-combination-has-stopped-working-for-a-few-numbers
|
// https://superuser.com/questions/1455762/ctrl-shift-number-key-combination-has-stopped-working-for-a-few-numbers
|
||||||
|
#[profiling::function]
|
||||||
fn handle_keydown_msg(
|
fn handle_keydown_msg(
|
||||||
handle: HWND,
|
handle: HWND,
|
||||||
wparam: WPARAM,
|
wparam: WPARAM,
|
||||||
|
@ -380,6 +382,8 @@ fn handle_keydown_msg(
|
||||||
state_ptr: Rc<WindowsWindowStatePtr>,
|
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||||
) -> Option<isize> {
|
) -> Option<isize> {
|
||||||
let mut lock = state_ptr.state.borrow_mut();
|
let mut lock = state_ptr.state.borrow_mut();
|
||||||
|
lock.keydown_time = Some(std::time::Instant::now());
|
||||||
|
println!("WM_KEYDOWN");
|
||||||
let Some(input) = handle_key_event(handle, wparam, lparam, &mut lock, |keystroke| {
|
let Some(input) = handle_key_event(handle, wparam, lparam, &mut lock, |keystroke| {
|
||||||
PlatformInput::KeyDown(KeyDownEvent {
|
PlatformInput::KeyDown(KeyDownEvent {
|
||||||
keystroke,
|
keystroke,
|
||||||
|
@ -1237,10 +1241,18 @@ fn draw_window(
|
||||||
.request_frame
|
.request_frame
|
||||||
.take()?;
|
.take()?;
|
||||||
request_frame(RequestFrameOptions {
|
request_frame(RequestFrameOptions {
|
||||||
require_presentation: false,
|
require_presentation: true,
|
||||||
force_render,
|
force_render,
|
||||||
});
|
});
|
||||||
state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame);
|
let mut lock = state_ptr.state.borrow_mut();
|
||||||
|
if let Some(keydown_time) = lock.keydown_time.take() {
|
||||||
|
let elapsed = keydown_time.elapsed();
|
||||||
|
println!(
|
||||||
|
"Elapsed keydown time: {:.02} ms",
|
||||||
|
elapsed.as_secs_f64() * 1000.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
lock.callbacks.request_frame = Some(request_frame);
|
||||||
unsafe { ValidateRect(Some(handle), None).ok().log_err() };
|
unsafe { ValidateRect(Some(handle), None).ok().log_err() };
|
||||||
Some(0)
|
Some(0)
|
||||||
}
|
}
|
||||||
|
@ -1292,6 +1304,7 @@ fn translate_message(handle: HWND, wparam: WPARAM, lparam: LPARAM) {
|
||||||
unsafe { TranslateMessage(&msg).ok().log_err() };
|
unsafe { TranslateMessage(&msg).ok().log_err() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[profiling::function]
|
||||||
fn handle_key_event<F>(
|
fn handle_key_event<F>(
|
||||||
handle: HWND,
|
handle: HWND,
|
||||||
wparam: WPARAM,
|
wparam: WPARAM,
|
||||||
|
|
|
@ -14,25 +14,27 @@ use itertools::Itertools;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use windows::{
|
use windows::{
|
||||||
UI::ViewManagement::UISettings,
|
core::*, Win32::{
|
||||||
Win32::{
|
|
||||||
Foundation::*,
|
Foundation::*,
|
||||||
Graphics::{
|
Graphics::{
|
||||||
|
DirectComposition::DCompositionWaitForCompositorClock,
|
||||||
|
Dxgi::{
|
||||||
|
CreateDXGIFactory2, IDXGIAdapter1, IDXGIFactory6, IDXGIOutput, DXGI_CREATE_FACTORY_FLAGS, DXGI_GPU_PREFERENCE_MINIMUM_POWER
|
||||||
|
},
|
||||||
Gdi::*,
|
Gdi::*,
|
||||||
Imaging::{CLSID_WICImagingFactory, IWICImagingFactory},
|
Imaging::{CLSID_WICImagingFactory, IWICImagingFactory},
|
||||||
},
|
},
|
||||||
Security::Credentials::*,
|
Security::Credentials::*,
|
||||||
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*},
|
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*},
|
||||||
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
|
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
|
||||||
},
|
}, UI::ViewManagement::UISettings
|
||||||
core::*,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub(crate) struct WindowsPlatform {
|
pub(crate) struct WindowsPlatform {
|
||||||
state: RefCell<WindowsPlatformState>,
|
state: RefCell<WindowsPlatformState>,
|
||||||
raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
|
raw_window_handles: Arc<RwLock<SmallVec<[SafeHwnd; 4]>>>,
|
||||||
// The below members will never change throughout the entire lifecycle of the app.
|
// The below members will never change throughout the entire lifecycle of the app.
|
||||||
icon: HICON,
|
icon: HICON,
|
||||||
main_receiver: flume::Receiver<Runnable>,
|
main_receiver: flume::Receiver<Runnable>,
|
||||||
|
@ -109,7 +111,7 @@ impl WindowsPlatform {
|
||||||
};
|
};
|
||||||
let icon = load_icon().unwrap_or_default();
|
let icon = load_icon().unwrap_or_default();
|
||||||
let state = RefCell::new(WindowsPlatformState::new());
|
let state = RefCell::new(WindowsPlatformState::new());
|
||||||
let raw_window_handles = RwLock::new(SmallVec::new());
|
let raw_window_handles = Arc::new(RwLock::new(SmallVec::new()));
|
||||||
let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
|
let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
|
@ -128,10 +130,29 @@ impl WindowsPlatform {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn begin_vsync_thread(&self) {
|
||||||
|
let raw_window_handles = self.raw_window_handles.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let vsync_provider = VSyncProvider::new();
|
||||||
|
loop {
|
||||||
|
unsafe {
|
||||||
|
// DCompositionWaitForCompositorClock(None, INFINITE);
|
||||||
|
vsync_provider.wait_for_vsync();
|
||||||
|
for handle in raw_window_handles.read().iter() {
|
||||||
|
RedrawWindow(Some(**handle), None, None, RDW_INVALIDATE)
|
||||||
|
.ok()
|
||||||
|
.log_err();
|
||||||
|
// PostMessageW(Some(**handle), WM_GPUI_FORCE_DRAW_WINDOW, WPARAM(0), LPARAM(0)).log_err();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn redraw_all(&self) {
|
fn redraw_all(&self) {
|
||||||
for handle in self.raw_window_handles.read().iter() {
|
for handle in self.raw_window_handles.read().iter() {
|
||||||
unsafe {
|
unsafe {
|
||||||
RedrawWindow(Some(*handle), None, None, RDW_INVALIDATE | RDW_UPDATENOW)
|
RedrawWindow(Some(**handle), None, None, RDW_INVALIDATE | RDW_UPDATENOW)
|
||||||
.ok()
|
.ok()
|
||||||
.log_err();
|
.log_err();
|
||||||
}
|
}
|
||||||
|
@ -142,8 +163,8 @@ impl WindowsPlatform {
|
||||||
self.raw_window_handles
|
self.raw_window_handles
|
||||||
.read()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.find(|entry| *entry == &hwnd)
|
.find(|entry| ***entry == hwnd)
|
||||||
.and_then(|hwnd| try_get_window_inner(*hwnd))
|
.and_then(|hwnd| try_get_window_inner(**hwnd))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -152,7 +173,7 @@ impl WindowsPlatform {
|
||||||
.read()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|handle| unsafe {
|
.for_each(|handle| unsafe {
|
||||||
PostMessageW(Some(*handle), message, wparam, lparam).log_err();
|
PostMessageW(Some(**handle), message, wparam, lparam).log_err();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,7 +181,7 @@ impl WindowsPlatform {
|
||||||
let mut lock = self.raw_window_handles.write();
|
let mut lock = self.raw_window_handles.write();
|
||||||
let index = lock
|
let index = lock
|
||||||
.iter()
|
.iter()
|
||||||
.position(|handle| *handle == target_window)
|
.position(|handle| **handle == target_window)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
lock.remove(index);
|
lock.remove(index);
|
||||||
|
|
||||||
|
@ -223,7 +244,8 @@ impl WindowsPlatform {
|
||||||
fn handle_events(&self) -> bool {
|
fn handle_events(&self) -> bool {
|
||||||
let mut msg = MSG::default();
|
let mut msg = MSG::default();
|
||||||
unsafe {
|
unsafe {
|
||||||
while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() {
|
// while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() {
|
||||||
|
while GetMessageW(&mut msg, None, 0, 0).as_bool() {
|
||||||
match msg.message {
|
match msg.message {
|
||||||
WM_QUIT => return true,
|
WM_QUIT => return true,
|
||||||
WM_INPUTLANGCHANGE
|
WM_INPUTLANGCHANGE
|
||||||
|
@ -305,11 +327,17 @@ impl WindowsPlatform {
|
||||||
if active_window_hwnd.is_invalid() {
|
if active_window_hwnd.is_invalid() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
self.raw_window_handles
|
if self
|
||||||
|
.raw_window_handles
|
||||||
.read()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.find(|&&hwnd| hwnd == active_window_hwnd)
|
.find(|&&hwnd| *hwnd == active_window_hwnd)
|
||||||
.copied()
|
.is_some()
|
||||||
|
{
|
||||||
|
Some(active_window_hwnd)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,12 +368,13 @@ impl Platform for WindowsPlatform {
|
||||||
|
|
||||||
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
|
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
|
||||||
on_finish_launching();
|
on_finish_launching();
|
||||||
loop {
|
self.begin_vsync_thread();
|
||||||
if self.handle_events() {
|
// loop {
|
||||||
break;
|
if self.handle_events() {
|
||||||
}
|
// break;
|
||||||
self.redraw_all();
|
|
||||||
}
|
}
|
||||||
|
// self.redraw_all();
|
||||||
|
// }
|
||||||
|
|
||||||
if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
|
if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
|
||||||
callback();
|
callback();
|
||||||
|
@ -438,7 +467,7 @@ impl Platform for WindowsPlatform {
|
||||||
) -> Result<Box<dyn PlatformWindow>> {
|
) -> Result<Box<dyn PlatformWindow>> {
|
||||||
let window = WindowsWindow::new(handle, options, self.generate_creation_info())?;
|
let window = WindowsWindow::new(handle, options, self.generate_creation_info())?;
|
||||||
let handle = window.get_raw_handle();
|
let handle = window.get_raw_handle();
|
||||||
self.raw_window_handles.write().push(handle);
|
self.raw_window_handles.write().push(handle.into());
|
||||||
|
|
||||||
Ok(Box::new(window))
|
Ok(Box::new(window))
|
||||||
}
|
}
|
||||||
|
@ -717,6 +746,46 @@ pub(crate) struct WindowCreationInfo {
|
||||||
pub(crate) main_thread_id_win32: u32,
|
pub(crate) main_thread_id_win32: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct VSyncProvider {
|
||||||
|
dxgi_output: IDXGIOutput,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VSyncProvider {
|
||||||
|
fn new() -> Self {
|
||||||
|
let dxgi_factory: IDXGIFactory6 =
|
||||||
|
unsafe { CreateDXGIFactory2(DXGI_CREATE_FACTORY_FLAGS::default()) }.unwrap();
|
||||||
|
let adapter: IDXGIAdapter1 = get_adapter(&dxgi_factory);
|
||||||
|
unsafe {
|
||||||
|
let dxgi_output = adapter.EnumOutputs(0).unwrap();
|
||||||
|
Self { dxgi_output }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_for_vsync(&self) {
|
||||||
|
unsafe {
|
||||||
|
self.dxgi_output.WaitForVBlank().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_adapter(dxgi_factory: &IDXGIFactory6) -> IDXGIAdapter1 {
|
||||||
|
unsafe {
|
||||||
|
for index in 0.. {
|
||||||
|
let adapter = dxgi_factory
|
||||||
|
.EnumAdapterByGpuPreference(index, DXGI_GPU_PREFERENCE_MINIMUM_POWER)
|
||||||
|
.unwrap();
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unreachable!("No DXGI adapter found")
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for VSyncProvider {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn open_target(target: &str) {
|
fn open_target(target: &str) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ret = ShellExecuteW(
|
let ret = ShellExecuteW(
|
||||||
|
|
|
@ -49,6 +49,7 @@ pub struct WindowsWindowState {
|
||||||
pub hovered: bool,
|
pub hovered: bool,
|
||||||
|
|
||||||
pub renderer: DirectXRenderer,
|
pub renderer: DirectXRenderer,
|
||||||
|
pub keydown_time: Option<std::time::Instant>,
|
||||||
|
|
||||||
pub click_state: ClickState,
|
pub click_state: ClickState,
|
||||||
pub system_settings: WindowsSystemSettings,
|
pub system_settings: WindowsSystemSettings,
|
||||||
|
@ -115,6 +116,7 @@ impl WindowsWindowState {
|
||||||
let nc_button_pressed = None;
|
let nc_button_pressed = None;
|
||||||
let fullscreen = None;
|
let fullscreen = None;
|
||||||
let initial_placement = None;
|
let initial_placement = None;
|
||||||
|
let keydown_time = None;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
origin,
|
origin,
|
||||||
|
@ -133,6 +135,7 @@ impl WindowsWindowState {
|
||||||
system_key_handled,
|
system_key_handled,
|
||||||
hovered,
|
hovered,
|
||||||
renderer,
|
renderer,
|
||||||
|
keydown_time,
|
||||||
click_state,
|
click_state,
|
||||||
system_settings,
|
system_settings,
|
||||||
current_cursor,
|
current_cursor,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use windows::Win32::{Foundation::HANDLE, UI::WindowsAndMessaging::HCURSOR};
|
use windows::Win32::{
|
||||||
|
Foundation::{HANDLE, HWND},
|
||||||
|
UI::WindowsAndMessaging::HCURSOR,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub(crate) struct SafeHandle {
|
pub(crate) struct SafeHandle {
|
||||||
|
@ -45,3 +48,31 @@ impl Deref for SafeCursor {
|
||||||
&self.raw
|
&self.raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub(crate) struct SafeHwnd {
|
||||||
|
raw: HWND,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for SafeHwnd {}
|
||||||
|
unsafe impl Sync for SafeHwnd {}
|
||||||
|
|
||||||
|
impl From<HWND> for SafeHwnd {
|
||||||
|
fn from(value: HWND) -> Self {
|
||||||
|
SafeHwnd { raw: value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SafeHwnd> for HWND {
|
||||||
|
fn from(value: SafeHwnd) -> Self {
|
||||||
|
value.raw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for SafeHwnd {
|
||||||
|
type Target = HWND;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.raw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue