mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-11 15:01:02 +03:00
fix: reuse the dxgi staging texture instead of one per frame
ohgodwhat() created a full screen D3D11_USAGE_STAGING texture for every captured frame and pinned each one with SetEvictionPriority(MAXIMUM). Because D3D11 resource destruction may be deferred, that per-frame churn can accumulate a large amount of graphics kernel paged pool on affected drivers. Keep a single staging texture and rebuild it only when the desktop image changes shape. Also check the IDXGISurface QueryInterface result, so a failure can no longer leave surface null while readable holds a valid texture. Reported in #15945. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011sw75MSAz7PTqrSALdStXe
This commit is contained in:
@@ -48,6 +48,7 @@ pub struct Capturer {
|
|||||||
duplication: ComPtr<IDXGIOutputDuplication>,
|
duplication: ComPtr<IDXGIOutputDuplication>,
|
||||||
fastlane: bool,
|
fastlane: bool,
|
||||||
surface: ComPtr<IDXGISurface>,
|
surface: ComPtr<IDXGISurface>,
|
||||||
|
readable: ComPtr<ID3D11Texture2D>,
|
||||||
texture: ComPtr<ID3D11Texture2D>,
|
texture: ComPtr<ID3D11Texture2D>,
|
||||||
width: usize,
|
width: usize,
|
||||||
height: usize,
|
height: usize,
|
||||||
@@ -163,6 +164,7 @@ impl Capturer {
|
|||||||
duplication: ComPtr(duplication),
|
duplication: ComPtr(duplication),
|
||||||
fastlane: desc.DesktopImageInSystemMemory == TRUE,
|
fastlane: desc.DesktopImageInSystemMemory == TRUE,
|
||||||
surface: ComPtr(ptr::null_mut()),
|
surface: ComPtr(ptr::null_mut()),
|
||||||
|
readable: ComPtr(ptr::null_mut()),
|
||||||
texture: ComPtr(ptr::null_mut()),
|
texture: ComPtr(ptr::null_mut()),
|
||||||
width: display.width() as usize,
|
width: display.width() as usize,
|
||||||
height: display.height() as usize,
|
height: display.height() as usize,
|
||||||
@@ -346,14 +348,14 @@ impl Capturer {
|
|||||||
if self.fastlane {
|
if self.fastlane {
|
||||||
wrap_hresult((*self.duplication.0).MapDesktopSurface(&mut rect))?;
|
wrap_hresult((*self.duplication.0).MapDesktopSurface(&mut rect))?;
|
||||||
} else {
|
} else {
|
||||||
self.surface = ComPtr(self.ohgodwhat(frame.0)?);
|
self.ohgodwhat(frame.0)?;
|
||||||
wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?;
|
wrap_hresult((*self.surface.0).Map(&mut rect, DXGI_MAP_READ))?;
|
||||||
}
|
}
|
||||||
Ok((rect.pBits, rect.Pitch))
|
Ok((rect.pBits, rect.Pitch))
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy from GPU memory to system memory
|
// copy from GPU memory to system memory
|
||||||
unsafe fn ohgodwhat(&mut self, frame: *mut IDXGIResource) -> io::Result<*mut IDXGISurface> {
|
unsafe fn ohgodwhat(&mut self, frame: *mut IDXGIResource) -> io::Result<()> {
|
||||||
let mut texture: *mut ID3D11Texture2D = ptr::null_mut();
|
let mut texture: *mut ID3D11Texture2D = ptr::null_mut();
|
||||||
(*frame).QueryInterface(
|
(*frame).QueryInterface(
|
||||||
&IID_ID3D11Texture2D,
|
&IID_ID3D11Texture2D,
|
||||||
@@ -370,24 +372,37 @@ impl Capturer {
|
|||||||
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
||||||
texture_desc.MiscFlags = 0;
|
texture_desc.MiscFlags = 0;
|
||||||
|
|
||||||
let mut readable = ptr::null_mut();
|
// Avoid per-frame staging texture allocation and the kernel allocation churn it causes.
|
||||||
wrap_hresult((*self.device.0).CreateTexture2D(
|
let mut current: D3D11_TEXTURE2D_DESC = mem::zeroed();
|
||||||
&mut texture_desc,
|
if !self.surface.is_null() {
|
||||||
ptr::null(),
|
(*self.readable.0).GetDesc(&mut current);
|
||||||
&mut readable,
|
}
|
||||||
))?;
|
if current.Width != texture_desc.Width
|
||||||
(*readable).SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
|
|| current.Height != texture_desc.Height
|
||||||
let readable = ComPtr(readable);
|
|| current.Format != texture_desc.Format
|
||||||
|
{
|
||||||
|
let mut readable = ptr::null_mut();
|
||||||
|
wrap_hresult((*self.device.0).CreateTexture2D(
|
||||||
|
&mut texture_desc,
|
||||||
|
ptr::null(),
|
||||||
|
&mut readable,
|
||||||
|
))?;
|
||||||
|
(*readable).SetEvictionPriority(DXGI_RESOURCE_PRIORITY_MAXIMUM);
|
||||||
|
let readable = ComPtr(readable);
|
||||||
|
|
||||||
let mut surface = ptr::null_mut();
|
let mut surface = ptr::null_mut();
|
||||||
(*readable.0).QueryInterface(
|
wrap_hresult((*readable.0).QueryInterface(
|
||||||
&IID_IDXGISurface,
|
&IID_IDXGISurface,
|
||||||
&mut surface as *mut *mut _ as *mut *mut _,
|
&mut surface as *mut *mut _ as *mut *mut _,
|
||||||
);
|
))?;
|
||||||
|
|
||||||
(*self.context.0).CopyResource(readable.0 as *mut _, texture.0 as *mut _);
|
self.readable = readable;
|
||||||
|
self.surface = ComPtr(surface);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(surface)
|
(*self.context.0).CopyResource(self.readable.0 as *mut _, texture.0 as *mut _);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn frame<'a>(&'a mut self, timeout: UINT) -> io::Result<Frame<'a>> {
|
pub fn frame<'a>(&'a mut self, timeout: UINT) -> io::Result<Frame<'a>> {
|
||||||
|
|||||||
Reference in New Issue
Block a user