处理DirectX 11纹理图像步幅的最有效方法是什么?

3
我正在尝试使用Windows Graphics Capture Api(windows-capture)构建一个屏幕捕获库,但是在处理映射缓冲区image stride时遇到了问题,这是每个RowPitch末尾的空缓冲区。目前我是这样处理的:
            let row_size = self.width as usize * std::mem::size_of::<Rgba>();

            for i in 0..self.height {
                unsafe {
                    ptr::copy_nonoverlapping(
                        mapped_resource
                            .pData
                            .add((i * mapped_resource.RowPitch) as usize)
                            as *mut u8,
                        self.buffer.add(i as usize * row_size),
                        row_size,
                    )
                };
            }

这个方法有点慢(在我的CPU上需要4毫秒),有没有办法在GPU上做,这样会更快一些?我试过使用计算着色器,但没有成功。

我基本上想要以最快的方式获取屏幕像素数据缓冲区,存储在一个[u8]中。

谢谢你的帮助。


在数据从GPU复制到CPU时,Map可能会阻塞。尝试先将数据复制到D3D11_USAGE_STAGING缓冲区,然后再映射该缓冲区。然而,您需要进行同步,即使用一个栅栏,以确保在映射之前复制操作已完成。 - undefined
@TomHuntington 地图和复制都可以,但问题是处理图像跨度太慢了。 - undefined
我听到你说的,但我觉得你不理解Mapping D3D11_USAGE_DEFAULTD3D11_USAGE_STAGING资源之间的区别。D3D11_USAGE_DEFAULT是由GPU支持的内存,当进行映射时,运行时会从GPU复制到CPU创建CPU支持的内存副本,然后阻塞等待复制完成,然后给你指针。为了避免阻塞,你需要将其复制到D3D11_USAGE_STAGING资源并进行映射。 - undefined
@TomHuntington 我正在使用 D3D11_USAGE_STAGING 纹理,然后复制资源,再进行映射。 - undefined
嗯,你确定在调用ptr::copy_nonoverlapping之前D3D11的复制已经完成了吗?可能发生了一些有趣的事情,请参考https://stackoverflow.com/a/75871029/11998382。 - undefined
也许尝试在不将代码复制到暂存纹理的情况下计时上述代码。也许,尝试用普通缓冲区(或者Rust中的其他叫法)替换mapped_resource。也许你的计时有问题,4毫秒太慢了。 - undefined
1个回答

0
为了加快从Windows图形捕获API传输屏幕像素数据到缓冲区的过程,采用基于GPU的技术可能不是最直接的方法。通常,GPU技术用于处理和渲染,而不是直接内存操作。
尝试:
use std::ptr;
use std::mem;

let row_size = self.width as usize * mem::size_of::<Rgba>();

for i in 0..self.height {
    let src = mapped_resource.pData.add((i * mapped_resource.RowPitch) as usize) as *const u8;
    let dest = self.buffer.add(i as usize * row_size);

    unsafe {
        // Using memcpy for optimized memory copy
        ptr::copy_nonoverlapping(src, dest as *mut u8, row_size);
    }
}

如果这个解决方案不起作用,请尝试以下方法:
- 多线程:如果没有实现,请考虑将内存复制操作并行化到多个线程中。 - 批处理:尝试优化获取或缓冲捕获的屏幕数据的方式。 - 直接内存映射:检查是否可以直接从GPU映射到您的缓冲区。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接