Implement hardware cursor #81

This commit is contained in:
Cherry
2024-03-27 12:11:15 -07:00
parent daf35938f3
commit b6286865eb
4 changed files with 102 additions and 17 deletions

View File

@@ -1,3 +1,3 @@
{
"rust-analyzer.check.command": "clippy"
"rust-analyzer.check.command": "clippy",
}

View File

@@ -81,6 +81,8 @@ Please see the [wiki](https://github.com/MolotovCherry/virtual-display-rs/wiki/V
3. Install [`cargo-make`](https://github.com/sagiegurari/cargo-make) if you don't have it
4. Install [`cargo-target-dir`](https://github.com/MolotovCherry/cargo-target-dir)
Make sure you generate your own windows code signing cert and install it according to "Installing the certificate" section.
You can build it with `cargo make build` (debug) or `cargo make -p prod build` (release), and check the `target/output` directory for all the files
To build the installer, do a `cargo make build-installer` (dev) or `cargo make -p prod build-installer` (release). In order to build the installer, you need [wix toolset](https://github.com/wixtoolset/wix3/releases) installed and on `Path`

View File

@@ -1,24 +1,29 @@
use std::{
ffi::c_void,
mem::{self, size_of},
num::{ParseIntError, TryFromIntError},
ptr::{addr_of_mut, NonNull},
};
use anyhow::anyhow;
use log::error;
use log::{error, warn};
use wdf_umdf::{
IddCxAdapterInitAsync, IddCxError, IddCxMonitorArrival, IddCxMonitorCreate, WdfError,
WdfObjectDelete, WDF_DECLARE_CONTEXT_TYPE,
IddCxAdapterInitAsync, IddCxError, IddCxMonitorArrival, IddCxMonitorCreate,
IddCxMonitorSetupHardwareCursor, WdfError, WdfObjectDelete, WDF_DECLARE_CONTEXT_TYPE,
};
use wdf_umdf_sys::{
DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY, HANDLE, IDARG_IN_ADAPTER_INIT, IDARG_IN_MONITORCREATE,
IDARG_OUT_ADAPTER_INIT, IDARG_OUT_MONITORARRIVAL, IDARG_OUT_MONITORCREATE, IDDCX_ADAPTER,
IDDCX_ADAPTER_CAPS, IDDCX_ENDPOINT_DIAGNOSTIC_INFO, IDDCX_ENDPOINT_VERSION,
IDDCX_FEATURE_IMPLEMENTATION, IDDCX_MONITOR, IDDCX_MONITOR_DESCRIPTION,
IDDCX_MONITOR_DESCRIPTION_TYPE, IDDCX_MONITOR_INFO, IDDCX_SWAPCHAIN, IDDCX_TRANSMISSION_TYPE,
LUID, NTSTATUS, WDFDEVICE, WDFOBJECT, WDF_OBJECT_ATTRIBUTES,
IDARG_IN_SETUP_HWCURSOR, IDARG_OUT_ADAPTER_INIT, IDARG_OUT_MONITORARRIVAL,
IDARG_OUT_MONITORCREATE, IDDCX_ADAPTER, IDDCX_ADAPTER_CAPS, IDDCX_CURSOR_CAPS,
IDDCX_ENDPOINT_DIAGNOSTIC_INFO, IDDCX_ENDPOINT_VERSION, IDDCX_FEATURE_IMPLEMENTATION,
IDDCX_MONITOR, IDDCX_MONITOR_DESCRIPTION, IDDCX_MONITOR_DESCRIPTION_TYPE, IDDCX_MONITOR_INFO,
IDDCX_SWAPCHAIN, IDDCX_TRANSMISSION_TYPE, IDDCX_XOR_CURSOR_SUPPORT, LUID, NTSTATUS, WDFDEVICE,
WDFOBJECT, WDF_OBJECT_ATTRIBUTES,
};
use windows::{
core::{s, w, GUID},
Win32::{Foundation::TRUE, System::Threading::CreateEventA},
};
use windows::core::{w, GUID};
use crate::{
direct_3d_device::Direct3DDevice,
@@ -250,6 +255,8 @@ impl MonitorContext {
processor.run(swap_chain, device, new_frame_event);
self.swap_chain_processor = Some(processor);
self.setup_hw_cursor();
} else {
// It's important to delete the swap-chain if D3D initialization fails, so that the OS knows to generate a new
// swap-chain and try again.
@@ -263,4 +270,40 @@ impl MonitorContext {
pub fn unassign_swap_chain(&mut self) {
self.swap_chain_processor.take();
}
pub fn setup_hw_cursor(&mut self) {
let mouse_event = unsafe { CreateEventA(None, false, false, s!("vdd_mouse_event")) };
let Ok(mouse_event) = mouse_event else {
error!("CreateEventA failed: {mouse_event:?}");
return;
};
// setup hardware cursor
let cursor_info = IDDCX_CURSOR_CAPS {
#[allow(clippy::cast_possible_truncation)]
Size: std::mem::size_of::<IDDCX_CURSOR_CAPS>() as u32,
AlphaCursorSupport: TRUE.0,
MaxX: 512,
MaxY: 512,
ColorXorCursorSupport: IDDCX_XOR_CURSOR_SUPPORT::IDDCX_XOR_CURSOR_SUPPORT_NONE,
};
let hw_cursor = IDARG_IN_SETUP_HWCURSOR {
CursorInfo: cursor_info,
hNewCursorDataAvailable: mouse_event.0 as *mut c_void,
};
let res = unsafe { IddCxMonitorSetupHardwareCursor(self.device, &hw_cursor) };
let Ok(res) = res else {
error!("IddCxMonitorSetupHardwareCursor() failed: {res:?}");
return;
};
if res.is_warning() {
warn!("IddCxMonitorSetupHardwareCursor() warn: {res:?}");
}
if res.is_error() {
error!("IddCxMonitorSetupHardwareCursor() failed: {res:?}");
}
}
}

View File

@@ -2,8 +2,9 @@
#![allow(clippy::missing_errors_doc)]
use wdf_umdf_sys::{
IDARG_IN_ADAPTER_INIT, IDARG_IN_MONITORCREATE, IDARG_IN_SWAPCHAINSETDEVICE,
IDARG_OUT_ADAPTER_INIT, IDARG_OUT_MONITORARRIVAL, IDARG_OUT_MONITORCREATE,
IDARG_IN_ADAPTER_INIT, IDARG_IN_MONITORCREATE, IDARG_IN_QUERY_HWCURSOR,
IDARG_IN_SETUP_HWCURSOR, IDARG_IN_SWAPCHAINSETDEVICE, IDARG_OUT_ADAPTER_INIT,
IDARG_OUT_MONITORARRIVAL, IDARG_OUT_MONITORCREATE, IDARG_OUT_QUERY_HWCURSOR,
IDARG_OUT_RELEASEANDACQUIREBUFFER, IDDCX_ADAPTER, IDDCX_MONITOR, IDDCX_SWAPCHAIN,
IDD_CX_CLIENT_CONFIG, NTSTATUS, WDFDEVICE, WDFDEVICE_INIT,
};
@@ -135,9 +136,9 @@ pub unsafe fn IddCxDeviceInitialize(
/// None. User is responsible for safety.
pub unsafe fn IddCxAdapterInitAsync(
// in
pInArgs: *const IDARG_IN_ADAPTER_INIT,
pInArgs: &IDARG_IN_ADAPTER_INIT,
// out
pOutArgs: *mut IDARG_OUT_ADAPTER_INIT,
pOutArgs: &mut IDARG_OUT_ADAPTER_INIT,
) -> Result<NTSTATUS, IddCxError> {
IddCxCall! {
IddCxAdapterInitAsync(
@@ -155,9 +156,9 @@ pub unsafe fn IddCxMonitorCreate(
// in
AdapterObject: IDDCX_ADAPTER,
// in
pInArgs: *const IDARG_IN_MONITORCREATE,
pInArgs: &IDARG_IN_MONITORCREATE,
// out
pOutArgs: *mut IDARG_OUT_MONITORCREATE,
pOutArgs: &mut IDARG_OUT_MONITORCREATE,
) -> Result<NTSTATUS, IddCxError> {
IddCxCall!(
IddCxMonitorCreate(
@@ -176,7 +177,7 @@ pub unsafe fn IddCxMonitorArrival(
// in
MonitorObject: IDDCX_MONITOR,
// out
pOutArgs: *mut IDARG_OUT_MONITORARRIVAL,
pOutArgs: &mut IDARG_OUT_MONITORARRIVAL,
) -> Result<NTSTATUS, IddCxError> {
IddCxCall!(
IddCxMonitorArrival(
@@ -254,3 +255,42 @@ pub unsafe fn IddCxMonitorDeparture(
)
)
}
/// # Safety
///
/// None. User is responsible for safety.
#[rustfmt::skip]
pub unsafe fn IddCxMonitorSetupHardwareCursor(
// in
MonitorObject: IDDCX_MONITOR,
// in
pInArgs: &IDARG_IN_SETUP_HWCURSOR
) -> Result<NTSTATUS, IddCxError> {
IddCxCall!(
IddCxMonitorSetupHardwareCursor(
MonitorObject,
pInArgs
)
)
}
/// # Safety
///
/// None. User is responsible for safety.
#[rustfmt::skip]
pub unsafe fn IddCxMonitorQueryHardwareCursor(
// in
MonitorObject: IDDCX_MONITOR,
// in
pInArgs: &IDARG_IN_QUERY_HWCURSOR,
// out
pOutArgs: &mut IDARG_OUT_QUERY_HWCURSOR
) -> Result<NTSTATUS, IddCxError> {
IddCxCall!(
IddCxMonitorQueryHardwareCursor(
MonitorObject,
pInArgs,
pOutArgs
)
)
}