enable dxgi https://github.com/rustdesk/rustdesk/issues/79, may fix https://github.com/rustdesk/rustdesk/issues/169
This commit is contained in:
parent
7282a462f4
commit
49dff161dd
@ -47,9 +47,9 @@ fn generate_bindings(
|
|||||||
) {
|
) {
|
||||||
let mut b = bindgen::builder()
|
let mut b = bindgen::builder()
|
||||||
.header(ffi_header.to_str().unwrap())
|
.header(ffi_header.to_str().unwrap())
|
||||||
.whitelist_type("^[vV].*")
|
.allowlist_type("^[vV].*")
|
||||||
.whitelist_var("^[vV].*")
|
.allowlist_var("^[vV].*")
|
||||||
.whitelist_function("^[vV].*")
|
.allowlist_function("^[vV].*")
|
||||||
.rustified_enum("^v.*")
|
.rustified_enum("^v.*")
|
||||||
.trust_clang_mangling(false)
|
.trust_clang_mangling(false)
|
||||||
.layout_tests(false) // breaks 32/64-bit compat
|
.layout_tests(false) // breaks 32/64-bit compat
|
||||||
|
@ -25,20 +25,35 @@ use winapi::{
|
|||||||
D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_USAGE_STAGING,
|
D3D11_CPU_ACCESS_READ, D3D11_SDK_VERSION, D3D11_USAGE_STAGING,
|
||||||
},
|
},
|
||||||
um::d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
|
um::d3dcommon::D3D_DRIVER_TYPE_UNKNOWN,
|
||||||
|
um::unknwnbase::IUnknown,
|
||||||
um::wingdi::*,
|
um::wingdi::*,
|
||||||
um::winnt::HRESULT,
|
um::winnt::HRESULT,
|
||||||
um::winuser::*,
|
um::winuser::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
//TODO: Split up into files.
|
pub struct ComPtr<T>(*mut T);
|
||||||
|
impl<T> ComPtr<T> {
|
||||||
|
fn is_null(&self) -> bool {
|
||||||
|
self.0.is_null()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<T> Drop for ComPtr<T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if !self.is_null() {
|
||||||
|
(*(self.0 as *mut IUnknown)).Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Capturer {
|
pub struct Capturer {
|
||||||
device: *mut ID3D11Device,
|
device: ComPtr<ID3D11Device>,
|
||||||
display: Display,
|
display: Display,
|
||||||
context: *mut ID3D11DeviceContext,
|
context: ComPtr<ID3D11DeviceContext>,
|
||||||
duplication: *mut IDXGIOutputDuplication,
|
duplication: ComPtr<IDXGIOutputDuplication>,
|
||||||
fastlane: bool,
|
fastlane: bool,
|
||||||
surface: *mut IDXGISurface,
|
surface: ComPtr<IDXGISurface>,
|
||||||
data: *const u8,
|
data: *const u8,
|
||||||
len: usize,
|
len: usize,
|
||||||
width: usize,
|
width: usize,
|
||||||
@ -62,7 +77,7 @@ impl Capturer {
|
|||||||
} else {
|
} else {
|
||||||
wrap_hresult(unsafe {
|
wrap_hresult(unsafe {
|
||||||
D3D11CreateDevice(
|
D3D11CreateDevice(
|
||||||
display.adapter as *mut _,
|
display.adapter.0 as *mut _,
|
||||||
D3D_DRIVER_TYPE_UNKNOWN,
|
D3D_DRIVER_TYPE_UNKNOWN,
|
||||||
ptr::null_mut(), // No software rasterizer.
|
ptr::null_mut(), // No software rasterizer.
|
||||||
0, // No device flags.
|
0, // No device flags.
|
||||||
@ -75,6 +90,8 @@ impl Capturer {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
let device = ComPtr(device);
|
||||||
|
let context = ComPtr(context);
|
||||||
|
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
gdi_capturer = display.create_gdi();
|
gdi_capturer = display.create_gdi();
|
||||||
@ -84,7 +101,7 @@ impl Capturer {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
res = wrap_hresult(unsafe {
|
res = wrap_hresult(unsafe {
|
||||||
let hres = (*display.inner).DuplicateOutput(device as *mut _, &mut duplication);
|
let hres = (*display.inner.0).DuplicateOutput(device.0 as *mut _, &mut duplication);
|
||||||
if hres != S_OK {
|
if hres != S_OK {
|
||||||
gdi_capturer = display.create_gdi();
|
gdi_capturer = display.create_gdi();
|
||||||
println!("Fallback to GDI");
|
println!("Fallback to GDI");
|
||||||
@ -124,17 +141,7 @@ impl Capturer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = res {
|
res?;
|
||||||
unsafe {
|
|
||||||
if !device.is_null() {
|
|
||||||
(*device).Release();
|
|
||||||
}
|
|
||||||
if !context.is_null() {
|
|
||||||
(*context).Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !duplication.is_null() {
|
if !duplication.is_null() {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -145,9 +152,9 @@ impl Capturer {
|
|||||||
Ok(Capturer {
|
Ok(Capturer {
|
||||||
device,
|
device,
|
||||||
context,
|
context,
|
||||||
duplication,
|
duplication: ComPtr(duplication),
|
||||||
fastlane: desc.DesktopImageInSystemMemory == TRUE,
|
fastlane: desc.DesktopImageInSystemMemory == TRUE,
|
||||||
surface: ptr::null_mut(),
|
surface: ComPtr(ptr::null_mut()),
|
||||||
width: display.width() as usize,
|
width: display.width() as usize,
|
||||||
height: display.height() as usize,
|
height: display.height() as usize,
|
||||||
display,
|
display,
|
||||||
@ -179,36 +186,23 @@ impl Capturer {
|
|||||||
let mut info = mem::MaybeUninit::uninit().assume_init();
|
let mut info = mem::MaybeUninit::uninit().assume_init();
|
||||||
self.data = ptr::null();
|
self.data = ptr::null();
|
||||||
|
|
||||||
wrap_hresult((*self.duplication).AcquireNextFrame(timeout, &mut info, &mut frame))?;
|
wrap_hresult((*self.duplication.0).AcquireNextFrame(timeout, &mut info, &mut frame))?;
|
||||||
|
let frame = ComPtr(frame);
|
||||||
|
|
||||||
if *info.LastPresentTime.QuadPart() == 0 {
|
if *info.LastPresentTime.QuadPart() == 0 {
|
||||||
return Err(std::io::ErrorKind::WouldBlock.into());
|
return Err(std::io::ErrorKind::WouldBlock.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut rect = mem::MaybeUninit::uninit().assume_init();
|
||||||
if self.fastlane {
|
if self.fastlane {
|
||||||
let mut rect = mem::MaybeUninit::uninit().assume_init();
|
wrap_hresult((*self.duplication.0).MapDesktopSurface(&mut rect))?;
|
||||||
let res = wrap_hresult((*self.duplication).MapDesktopSurface(&mut rect));
|
|
||||||
|
|
||||||
(*frame).Release();
|
|
||||||
|
|
||||||
if let Err(err) = res {
|
|
||||||
Err(err)
|
|
||||||
} else {
|
|
||||||
self.data = rect.pBits;
|
|
||||||
self.len = self.height * rect.Pitch as usize;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.surface = ptr::null_mut();
|
self.surface = ComPtr(self.ohgodwhat(frame.0)?);
|
||||||
self.surface = self.ohgodwhat(frame)?;
|
wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?;
|
||||||
|
|
||||||
let mut rect = mem::MaybeUninit::uninit().assume_init();
|
|
||||||
wrap_hresult((*self.surface).Map(&mut rect, DXGI_MAP_READ))?;
|
|
||||||
|
|
||||||
self.data = rect.pBits;
|
|
||||||
self.len = self.height * rect.Pitch as usize;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
self.data = rect.pBits;
|
||||||
|
self.len = self.height * rect.Pitch as usize;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy from GPU memory to system memory
|
// copy from GPU memory to system memory
|
||||||
@ -218,9 +212,10 @@ impl Capturer {
|
|||||||
&IID_ID3D11Texture2D,
|
&IID_ID3D11Texture2D,
|
||||||
&mut texture as *mut *mut _ as *mut *mut _,
|
&mut texture as *mut *mut _ as *mut *mut _,
|
||||||
);
|
);
|
||||||
|
let texture = ComPtr(texture);
|
||||||
|
|
||||||
let mut texture_desc = mem::MaybeUninit::uninit().assume_init();
|
let mut texture_desc = mem::MaybeUninit::uninit().assume_init();
|
||||||
(*texture).GetDesc(&mut texture_desc);
|
(*texture.0).GetDesc(&mut texture_desc);
|
||||||
|
|
||||||
texture_desc.Usage = D3D11_USAGE_STAGING;
|
texture_desc.Usage = D3D11_USAGE_STAGING;
|
||||||
texture_desc.BindFlags = 0;
|
texture_desc.BindFlags = 0;
|
||||||
@ -228,33 +223,23 @@ impl Capturer {
|
|||||||
texture_desc.MiscFlags = 0;
|
texture_desc.MiscFlags = 0;
|
||||||
|
|
||||||
let mut readable = ptr::null_mut();
|
let mut readable = ptr::null_mut();
|
||||||
let res = wrap_hresult((*self.device).CreateTexture2D(
|
wrap_hresult((*self.device.0).CreateTexture2D(
|
||||||
&mut texture_desc,
|
&mut texture_desc,
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
&mut readable,
|
&mut readable,
|
||||||
));
|
))?;
|
||||||
|
(*readable).SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
|
||||||
|
let readable = ComPtr(readable);
|
||||||
|
|
||||||
if let Err(err) = res {
|
let mut surface = ptr::null_mut();
|
||||||
(*frame).Release();
|
(*readable.0).QueryInterface(
|
||||||
(*texture).Release();
|
&IID_IDXGISurface,
|
||||||
(*readable).Release();
|
&mut surface as *mut *mut _ as *mut *mut _,
|
||||||
Err(err)
|
);
|
||||||
} else {
|
|
||||||
(*readable).SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
|
|
||||||
|
|
||||||
let mut surface = ptr::null_mut();
|
(*self.context.0).CopyResource(readable.0 as *mut _, texture.0 as *mut _);
|
||||||
(*readable).QueryInterface(
|
|
||||||
&IID_IDXGISurface,
|
|
||||||
&mut surface as *mut *mut _ as *mut *mut _,
|
|
||||||
);
|
|
||||||
|
|
||||||
(*self.context).CopyResource(readable as *mut _, texture as *mut _);
|
Ok(surface)
|
||||||
|
|
||||||
(*frame).Release();
|
|
||||||
(*texture).Release();
|
|
||||||
(*readable).Release();
|
|
||||||
Ok(surface)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame<'a>(&'a mut self, timeout: UINT) -> io::Result<&'a [u8]> {
|
pub fn frame<'a>(&'a mut self, timeout: UINT) -> io::Result<&'a [u8]> {
|
||||||
@ -271,17 +256,7 @@ impl Capturer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if self.fastlane {
|
self.unmap();
|
||||||
(*self.duplication).UnMapDesktopSurface();
|
|
||||||
} else {
|
|
||||||
if !self.surface.is_null() {
|
|
||||||
(*self.surface).Unmap();
|
|
||||||
(*self.surface).Release();
|
|
||||||
self.surface = ptr::null_mut();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(*self.duplication).ReleaseFrame();
|
|
||||||
self.load_frame(timeout)?;
|
self.load_frame(timeout)?;
|
||||||
slice::from_raw_parts(self.data, self.len)
|
slice::from_raw_parts(self.data, self.len)
|
||||||
}
|
}
|
||||||
@ -301,31 +276,32 @@ impl Capturer {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Capturer {
|
fn unmap(&self) {
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
if !self.surface.is_null() {
|
(*self.duplication.0).ReleaseFrame();
|
||||||
(*self.surface).Unmap();
|
if self.fastlane {
|
||||||
(*self.surface).Release();
|
(*self.duplication.0).UnMapDesktopSurface();
|
||||||
}
|
} else {
|
||||||
if !self.duplication.is_null() {
|
if !self.surface.is_null() {
|
||||||
(*self.duplication).Release();
|
(*self.surface.0).Unmap();
|
||||||
}
|
}
|
||||||
if !self.device.is_null() {
|
|
||||||
(*self.device).Release();
|
|
||||||
}
|
|
||||||
if !self.context.is_null() {
|
|
||||||
(*self.context).Release();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Capturer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !self.duplication.is_null() {
|
||||||
|
self.unmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Displays {
|
pub struct Displays {
|
||||||
factory: *mut IDXGIFactory1,
|
factory: ComPtr<IDXGIFactory1>,
|
||||||
adapter: *mut IDXGIAdapter1,
|
adapter: ComPtr<IDXGIAdapter1>,
|
||||||
/// Index of the CURRENT adapter.
|
/// Index of the CURRENT adapter.
|
||||||
nadapter: UINT,
|
nadapter: UINT,
|
||||||
/// Index of the NEXT display to fetch.
|
/// Index of the NEXT display to fetch.
|
||||||
@ -345,8 +321,8 @@ impl Displays {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(Displays {
|
Ok(Displays {
|
||||||
factory,
|
factory: ComPtr(factory),
|
||||||
adapter,
|
adapter: ComPtr(adapter),
|
||||||
nadapter: 0,
|
nadapter: 0,
|
||||||
ndisplay: 0,
|
ndisplay: 0,
|
||||||
})
|
})
|
||||||
@ -370,8 +346,8 @@ impl Displays {
|
|||||||
}
|
}
|
||||||
// let is_primary = (d.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) > 0;
|
// let is_primary = (d.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) > 0;
|
||||||
let mut disp = Display {
|
let mut disp = Display {
|
||||||
inner: std::ptr::null_mut(),
|
inner: ComPtr(std::ptr::null_mut()),
|
||||||
adapter: std::ptr::null_mut(),
|
adapter: ComPtr(std::ptr::null_mut()),
|
||||||
desc: unsafe { std::mem::zeroed() },
|
desc: unsafe { std::mem::zeroed() },
|
||||||
gdi: true,
|
gdi: true,
|
||||||
};
|
};
|
||||||
@ -416,18 +392,15 @@ impl Displays {
|
|||||||
|
|
||||||
let output = unsafe {
|
let output = unsafe {
|
||||||
let mut output = ptr::null_mut();
|
let mut output = ptr::null_mut();
|
||||||
(*self.adapter).EnumOutputs(self.ndisplay, &mut output);
|
(*self.adapter.0).EnumOutputs(self.ndisplay, &mut output);
|
||||||
output
|
ComPtr(output)
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the current adapter is done, we free it.
|
// If the current adapter is done, we free it.
|
||||||
// We return None so the caller gets the next adapter and tries again.
|
// We return None so the caller gets the next adapter and tries again.
|
||||||
|
|
||||||
if output.is_null() {
|
if output.is_null() {
|
||||||
unsafe {
|
self.adapter = ComPtr(ptr::null_mut());
|
||||||
(*self.adapter).Release();
|
|
||||||
self.adapter = ptr::null_mut();
|
|
||||||
}
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +412,7 @@ impl Displays {
|
|||||||
|
|
||||||
let desc = unsafe {
|
let desc = unsafe {
|
||||||
let mut desc = mem::MaybeUninit::uninit().assume_init();
|
let mut desc = mem::MaybeUninit::uninit().assume_init();
|
||||||
(*output).GetDesc(&mut desc);
|
(*output.0).GetDesc(&mut desc);
|
||||||
desc
|
desc
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -447,28 +420,24 @@ impl Displays {
|
|||||||
|
|
||||||
let mut inner: *mut IDXGIOutput1 = ptr::null_mut();
|
let mut inner: *mut IDXGIOutput1 = ptr::null_mut();
|
||||||
unsafe {
|
unsafe {
|
||||||
(*output).QueryInterface(&IID_IDXGIOutput1, &mut inner as *mut *mut _ as *mut *mut _);
|
(*output.0).QueryInterface(&IID_IDXGIOutput1, &mut inner as *mut *mut _ as *mut *mut _);
|
||||||
(*output).Release();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's null, we have an error.
|
// If it's null, we have an error.
|
||||||
// So we act like the adapter is done.
|
// So we act like the adapter is done.
|
||||||
|
|
||||||
if inner.is_null() {
|
if inner.is_null() {
|
||||||
unsafe {
|
self.adapter = ComPtr(ptr::null_mut());
|
||||||
(*self.adapter).Release();
|
|
||||||
self.adapter = ptr::null_mut();
|
|
||||||
}
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.adapter).AddRef();
|
(*self.adapter.0).AddRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Some(Display {
|
Some(Some(Display {
|
||||||
inner,
|
inner: ComPtr(inner),
|
||||||
adapter: self.adapter,
|
adapter: ComPtr(self.adapter.0),
|
||||||
desc,
|
desc,
|
||||||
gdi: false,
|
gdi: false,
|
||||||
}))
|
}))
|
||||||
@ -488,8 +457,8 @@ impl Iterator for Displays {
|
|||||||
|
|
||||||
self.adapter = unsafe {
|
self.adapter = unsafe {
|
||||||
let mut adapter = ptr::null_mut();
|
let mut adapter = ptr::null_mut();
|
||||||
(*self.factory).EnumAdapters1(self.nadapter, &mut adapter);
|
(*self.factory.0).EnumAdapters1(self.nadapter, &mut adapter);
|
||||||
adapter
|
ComPtr(adapter)
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(res) = self.read_and_invalidate() {
|
if let Some(res) = self.read_and_invalidate() {
|
||||||
@ -502,20 +471,9 @@ impl Iterator for Displays {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Displays {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
unsafe {
|
|
||||||
(*self.factory).Release();
|
|
||||||
if !self.adapter.is_null() {
|
|
||||||
(*self.adapter).Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Display {
|
pub struct Display {
|
||||||
inner: *mut IDXGIOutput1,
|
inner: ComPtr<IDXGIOutput1>,
|
||||||
adapter: *mut IDXGIAdapter1,
|
adapter: ComPtr<IDXGIAdapter1>,
|
||||||
desc: DXGI_OUTPUT_DESC,
|
desc: DXGI_OUTPUT_DESC,
|
||||||
gdi: bool,
|
gdi: bool,
|
||||||
}
|
}
|
||||||
@ -569,18 +527,6 @@ impl Display {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Display {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if self.inner.is_null() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
(*self.inner).Release();
|
|
||||||
(*self.adapter).Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wrap_hresult(x: HRESULT) -> io::Result<()> {
|
fn wrap_hresult(x: HRESULT) -> io::Result<()> {
|
||||||
use std::io::ErrorKind::*;
|
use std::io::ErrorKind::*;
|
||||||
Err((match x {
|
Err((match x {
|
||||||
|
@ -99,23 +99,9 @@ fn run(sp: GenericService) -> ResultType<()> {
|
|||||||
*SWITCH.lock().unwrap() = false;
|
*SWITCH.lock().unwrap() = false;
|
||||||
sp.send(msg_out);
|
sp.send(msg_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
if !c.is_gdi() {
|
|
||||||
// dxgi duplicateoutput has no output if display no change, so we use gdi this as workaround
|
|
||||||
if c.set_gdi() {
|
|
||||||
// dgx capture release has memory leak somehow, so use gdi always before fixing it, just sacrificing some cpu
|
|
||||||
/*
|
|
||||||
if let Ok(frame) = c.frame(wait as _) {
|
|
||||||
handle_one_frame(&sp, &frame, 0, &mut vpx)?;
|
|
||||||
}
|
|
||||||
c.cancel_gdi();
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let start = time::Instant::now();
|
|
||||||
let mut crc = (0, 0);
|
let mut crc = (0, 0);
|
||||||
|
let start = time::Instant::now();
|
||||||
let mut last_sent = time::Instant::now();
|
let mut last_sent = time::Instant::now();
|
||||||
let mut last_check_displays = time::Instant::now();
|
let mut last_check_displays = time::Instant::now();
|
||||||
while sp.ok() {
|
while sp.ok() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user