From 09d4f4a65a71f0de4a9f014bcf4097304a5ac625 Mon Sep 17 00:00:00 2001 From: Lazy Panda Date: Sat, 19 Oct 2024 12:23:56 +0800 Subject: [PATCH] zero copy and get direct3d device and context --- examples/basic.rs | 4 ++-- examples/cli.rs | 25 +++++-------------- src/capture.rs | 40 ++++++++++++++++++++++++++++--- src/encoder.rs | 8 +++++-- src/frame.rs | 30 +++++++++++------------ src/graphics_capture_api.rs | 5 ++-- windows-capture-python/src/lib.rs | 6 ++++- 7 files changed, 73 insertions(+), 45 deletions(-) diff --git a/examples/basic.rs b/examples/basic.rs index 7909692..784685f 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -4,7 +4,7 @@ use std::{ }; use windows_capture::{ - capture::GraphicsCaptureApiHandler, + capture::{GraphicsCaptureApiHandler, RawDirect3DDevice}, encoder::{AudioSettingsBuilder, ContainerSettingsBuilder, VideoEncoder, VideoSettingsBuilder}, frame::Frame, graphics_capture_api::InternalCaptureControl, @@ -28,7 +28,7 @@ impl GraphicsCaptureApiHandler for Capture { type Error = Box; // Function that will be called to create the struct. The flags can be passed from settings. - fn new(message: Self::Flags) -> Result { + fn new(_: RawDirect3DDevice, message: Self::Flags) -> Result { println!("Got The Flag: {message}"); let encoder = VideoEncoder::new( diff --git a/examples/cli.rs b/examples/cli.rs index 45c2cd0..d888dd4 100644 --- a/examples/cli.rs +++ b/examples/cli.rs @@ -10,10 +10,8 @@ use std::{ use clap::Parser; use windows_capture::{ - capture::GraphicsCaptureApiHandler, - encoder::{ - AudioSettingsBuilder, ContainerSettingsBuilder, VideoEncoder, VideoSettingsBuilder, - }, + capture::{GraphicsCaptureApiHandler, RawDirect3DDevice}, + encoder::{AudioSettingsBuilder, ContainerSettingsBuilder, VideoEncoder, VideoSettingsBuilder}, frame::Frame, graphics_capture_api::InternalCaptureControl, monitor::Monitor, @@ -55,7 +53,7 @@ impl GraphicsCaptureApiHandler for Capture { type Error = Box; // Function that will be called to create the struct. The flags can be passed from settings. - fn new(settings: Self::Flags) -> Result { + fn new(_: RawDirect3DDevice, settings: Self::Flags) -> Result { println!("Capture started."); let video_settings = VideoSettingsBuilder::new(settings.width, settings.height) @@ -226,8 +224,7 @@ fn main() { if let Some(window_name) = cli.window_name { // May use Window::foreground() instead - let capture_item = - Window::from_contains_name(&window_name).expect("Window not found!"); + let capture_item = Window::from_contains_name(&window_name).expect("Window not found!"); // Automatically detect window's width and height let rect = capture_item.rect().expect("Failed to get window rect"); @@ -249,12 +246,7 @@ fn main() { ); println!("Window size: {}x{}", width, height); - start_capture( - capture_item, - cursor_capture, - draw_border, - capture_settings, - ); + start_capture(capture_item, cursor_capture, draw_border, capture_settings); } else if let Some(index) = cli.monitor_index { // May use Monitor::primary() instead let capture_item = @@ -276,12 +268,7 @@ fn main() { println!("Monitor index: {}", index); println!("Monitor size: {}x{}", width, height); - start_capture( - capture_item, - cursor_capture, - draw_border, - capture_settings, - ); + start_capture(capture_item, cursor_capture, draw_border, capture_settings); } else { eprintln!("Either --window-name or --monitor-index must be provided"); std::process::exit(1); diff --git a/src/capture.rs b/src/capture.rs index 5abe35a..1d4f6e4 100644 --- a/src/capture.rs +++ b/src/capture.rs @@ -14,6 +14,7 @@ use windows::{ Graphics::Capture::GraphicsCaptureItem, Win32::{ Foundation::{HANDLE, LPARAM, WPARAM}, + Graphics::Direct3D11::{ID3D11Device, ID3D11DeviceContext}, System::{ Threading::{GetCurrentThreadId, GetThreadId}, WinRT::{ @@ -29,6 +30,7 @@ use windows::{ }; use crate::{ + d3d11::{self, create_d3d_device}, frame::Frame, graphics_capture_api::{self, GraphicsCaptureApi, InternalCaptureControl}, settings::Settings, @@ -207,6 +209,8 @@ pub enum GraphicsCaptureApiError { FailedToSetDispatcherQueueCompletedHandler, #[error("Failed to convert item to GraphicsCaptureItem")] ItemConvertFailed, + #[error("DirectX error: {0}")] + DirectXError(#[from] d3d11::Error), #[error("Graphics capture error: {0}")] GraphicsCaptureApiError(graphics_capture_api::Error), #[error("New handler error: {0}")] @@ -261,10 +265,20 @@ pub trait GraphicsCaptureApiHandler: Sized { // Get current thread ID let thread_id = unsafe { GetCurrentThreadId() }; + // Create direct3d device and context + let (d3d_device, d3d_device_context) = create_d3d_device()?; + // Start capture let result = Arc::new(Mutex::new(None)); let callback = Arc::new(Mutex::new( - Self::new(settings.flags).map_err(GraphicsCaptureApiError::NewHandlerError)?, + Self::new( + RawDirect3DDevice { + device: d3d_device.clone(), + context: d3d_device_context.clone(), + }, + settings.flags, + ) + .map_err(GraphicsCaptureApiError::NewHandlerError)?, )); let item = settings @@ -273,6 +287,8 @@ pub trait GraphicsCaptureApiHandler: Sized { .map_err(|_| GraphicsCaptureApiError::ItemConvertFailed)?; let mut capture = GraphicsCaptureApi::new( + d3d_device, + d3d_device_context, item, callback, settings.cursor_capture, @@ -374,10 +390,20 @@ pub trait GraphicsCaptureApiHandler: Sized { // Get current thread ID let thread_id = unsafe { GetCurrentThreadId() }; + // Create direct3d device and context + let (d3d_device, d3d_device_context) = create_d3d_device()?; + // Start capture let result = Arc::new(Mutex::new(None)); let callback = Arc::new(Mutex::new( - Self::new(settings.flags).map_err(GraphicsCaptureApiError::NewHandlerError)?, + Self::new( + RawDirect3DDevice { + device: d3d_device.clone(), + context: d3d_device_context.clone(), + }, + settings.flags, + ) + .map_err(GraphicsCaptureApiError::NewHandlerError)?, )); let item = settings @@ -386,6 +412,8 @@ pub trait GraphicsCaptureApiHandler: Sized { .map_err(|_| GraphicsCaptureApiError::ItemConvertFailed)?; let mut capture = GraphicsCaptureApi::new( + d3d_device, + d3d_device_context, item, callback.clone(), settings.cursor_capture, @@ -485,7 +513,7 @@ pub trait GraphicsCaptureApiHandler: Sized { /// # Returns /// /// Returns `Ok(Self)` if the struct creation was successful, otherwise returns an error of type `Self::Error`. - fn new(flags: Self::Flags) -> Result; + fn new(device: RawDirect3DDevice, flags: Self::Flags) -> Result; /// Called every time a new frame is available. /// @@ -513,3 +541,9 @@ pub trait GraphicsCaptureApiHandler: Sized { Ok(()) } } + +#[derive(Clone)] +pub struct RawDirect3DDevice { + pub device: ID3D11Device, + pub context: ID3D11DeviceContext, +} diff --git a/src/encoder.rs b/src/encoder.rs index f131625..82908c3 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -991,7 +991,9 @@ impl VideoEncoder { }; self.frame_sender.send(Some(( - VideoEncoderSource::DirectX(SendDirectX::new(unsafe { frame.as_raw_surface() })), + VideoEncoderSource::DirectX(SendDirectX::new(unsafe { + frame.as_raw_surface().clone() + })), timespan, )))?; @@ -1051,7 +1053,9 @@ impl VideoEncoder { }; self.frame_sender.send(Some(( - VideoEncoderSource::DirectX(SendDirectX::new(unsafe { frame.as_raw_surface() })), + VideoEncoderSource::DirectX(SendDirectX::new(unsafe { + frame.as_raw_surface().clone() + })), timespan, )))?; diff --git a/src/frame.rs b/src/frame.rs index fc9679b..81cd615 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -168,8 +168,8 @@ impl<'a> Frame<'a> { /// This method is unsafe because it returns a raw pointer to the IDirect3DSurface. #[must_use] #[inline] - pub unsafe fn as_raw_surface(&self) -> IDirect3DSurface { - self.frame_surface.clone() + pub unsafe fn as_raw_surface(&self) -> &IDirect3DSurface { + &self.frame_surface } /// Get the raw texture of the frame. @@ -178,7 +178,17 @@ impl<'a> Frame<'a> { /// /// The ID3D11Texture2D representing the raw texture of the frame. #[inline] - pub fn texture(&self) -> Result { + pub unsafe fn as_raw_texture(&self) -> &ID3D11Texture2D { + &self.frame_texture + } + + /// Get the frame buffer. + /// + /// # Returns + /// + /// The FrameBuffer containing the frame data. + #[inline] + pub fn buffer(&mut self) -> Result { // Texture Settings let texture_desc = D3D11_TEXTURE2D_DESC { Width: self.width, @@ -192,7 +202,7 @@ impl<'a> Frame<'a> { }, Usage: D3D11_USAGE_STAGING, BindFlags: 0, - CPUAccessFlags: D3D11_CPU_ACCESS_READ.0 as u32 | D3D11_CPU_ACCESS_WRITE.0 as u32, + CPUAccessFlags: D3D11_CPU_ACCESS_READ.0 as u32, MiscFlags: 0, }; @@ -210,18 +220,6 @@ impl<'a> Frame<'a> { self.context.CopyResource(&texture, &self.frame_texture); }; - Ok(texture) - } - - /// Get the frame buffer. - /// - /// # Returns - /// - /// The FrameBuffer containing the frame data. - #[inline] - pub fn buffer(&mut self) -> Result { - let texture = self.texture()?; - // Map the texture to enable CPU access let mut mapped_resource = D3D11_MAPPED_SUBRESOURCE::default(); unsafe { diff --git a/src/graphics_capture_api.rs b/src/graphics_capture_api.rs index a7a98ec..b36305e 100644 --- a/src/graphics_capture_api.rs +++ b/src/graphics_capture_api.rs @@ -23,7 +23,7 @@ use windows::{ use crate::{ capture::GraphicsCaptureApiHandler, - d3d11::{self, create_d3d_device, create_direct3d_device, SendDirectX}, + d3d11::{self, create_direct3d_device, SendDirectX}, frame::Frame, settings::{ColorFormat, CursorCaptureSettings, DrawBorderSettings}, }; @@ -117,6 +117,8 @@ impl GraphicsCaptureApi { T: GraphicsCaptureApiHandler + Send + 'static, E: Send + Sync + 'static, >( + d3d_device: ID3D11Device, + d3d_device_context: ID3D11DeviceContext, item: GraphicsCaptureItem, callback: Arc>, cursor_capture: CursorCaptureSettings, @@ -141,7 +143,6 @@ impl GraphicsCaptureApi { } // Create DirectX devices - let (d3d_device, d3d_device_context) = create_d3d_device()?; let direct3d_device = create_direct3d_device(&d3d_device)?; let pixel_format = DirectXPixelFormat(color_format as i32); diff --git a/windows-capture-python/src/lib.rs b/windows-capture-python/src/lib.rs index 8c7ebeb..78b21bf 100644 --- a/windows-capture-python/src/lib.rs +++ b/windows-capture-python/src/lib.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use ::windows_capture::{ capture::{ CaptureControl, CaptureControlError, GraphicsCaptureApiError, GraphicsCaptureApiHandler, + RawDirect3DDevice, }, frame::{self, Frame}, graphics_capture_api::InternalCaptureControl, @@ -368,7 +369,10 @@ impl GraphicsCaptureApiHandler for InnerNativeWindowsCapture { type Error = InnerNativeWindowsCaptureError; #[inline] - fn new((on_frame_arrived_callback, on_closed): Self::Flags) -> Result { + fn new( + _: RawDirect3DDevice, + (on_frame_arrived_callback, on_closed): Self::Flags, + ) -> Result { Ok(Self { on_frame_arrived_callback, on_closed,