You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用C#+DirectX11截图仅得到空Span的问题排查

使用Silk.NET.Direct3D11实现DX11截图时ReadOnlySpan为空的问题

我使用Silk.NET.Direct3D11库在C#中通过DirectX11实现截图功能,执行过程无报错,但最终得到的ReadOnlySpan<byte>为空。我尝试过创建中间Texture2D,先将desktopTexture复制到中间Texture2D,再复制到stagingResource的方案,问题仍未解决,相关代码如下:

//....
ID3D11Device* device=null;
ID3D11DeviceContext* context=null;
D3DFeatureLevel featureLevel=D3DFeatureLevel.Level101;
D3DFeatureLevel[] featureLevels =
[
    D3DFeatureLevel.Level111, D3DFeatureLevel.Level110, D3DFeatureLevel.Level101,D3DFeatureLevel.Level100
];
fixed (D3DFeatureLevel* pFeatureLevels = &featureLevels[0])
{
    D3D11 d3D11 = new D3D11(new DefaultNativeContext("d3d11"));
    if (d3D11.CreateDevice((IDXGIAdapter*)adapter1, D3DDriverType.Unknown, IntPtr.Zero,
            (uint)CreateDeviceFlag.None,pFeatureLevels,(uint)featureLevels.Length, D3D11.SdkVersion, ref device,
&featureLevel, ref context)!=0){/*..*/}
}
ID3D11DeviceContext* immediateContext = null;
device->GetImmediateContext(ref immediateContext);
IDXGIOutputDuplication *outputDuplication = null;
if (output5.DuplicateOutput((IUnknown*)device, ref outputDuplication)!=0){/*..*/}
OutduplFrameInfo outduplFrameInfo = new OutduplFrameInfo();
IDXGIResource* desktopResource = null;
if (outputDuplication->AcquireNextFrame(1000, &outduplFrameInfo, &desktopResource)!=0){/*..*/}
if (desktopResource->QueryInterface<ID3D11Resource>(out var desktopTexture)!=0){/*..*/}
Texture2DDesc stagingTextureDesc = new()
{
    CPUAccessFlags = (uint)CpuAccessFlag.Read,
    BindFlags = (uint)(BindFlag.None),
    Format = Format.FormatB8G8R8A8Unorm,
    Width = (uint)desc.DesktopCoordinates.Size.X,
    Height = (uint)desc.DesktopCoordinates.Size.Y,
    MiscFlags = (uint)ResourceMiscFlag.None,
    MipLevels = 1,
    ArraySize = 1,
    SampleDesc = { Count = 1, Quality = 0 },
    Usage = Usage.Staging
};
ID3D11Texture2D* stagingTexture = null;
if (device->CreateTexture2D(&stagingTextureDesc,null,ref stagingTexture )!=0){/*..*/}
stagingTexture->QueryInterface<ID3D11Resource>(out var stagingResource);
immediateContext->CopyResource(stagingResource, desktopTexture);
MappedSubresource mappedSubresource=new MappedSubresource();
if (immediateContext->Map(stagingResource, 0, Map.Read, 0, &mappedSubresource)!=0){/*..*/}
var span = new ReadOnlySpan<byte>(mappedSubresource.PData,
    (int)mappedSubresource.DepthPitch);

错误点及修复方案

1. 纹理格式不匹配导致复制失败

桌面复制得到的desktopTexture格式不一定是FormatB8G8R8A8Unorm,硬编码staging纹理格式会导致CopyResource静默失败(无报错但无数据复制)。

修复:
先获取桌面纹理的实际格式,再创建对应格式的staging纹理:

// 获取桌面纹理的描述
Texture2DDesc desktopDesc;
((ID3D11Texture2D*)desktopTexture)->GetDesc(&desktopDesc);

// 基于桌面纹理格式创建staging纹理
Texture2DDesc stagingTextureDesc = new()
{
    CPUAccessFlags = (uint)CpuAccessFlag.Read,
    BindFlags = 0,
    Format = desktopDesc.Format, // 使用桌面纹理的原生格式
    Width = desktopDesc.Width,
    Height = desktopDesc.Height,
    MiscFlags = 0,
    MipLevels = 1,
    ArraySize = 1,
    SampleDesc = { Count = 1, Quality = 0 },
    Usage = Usage.Staging
};

2. Span长度计算错误

MappedSubresource.DepthPitch是深度纹理每个切片的字节数,对于普通2D纹理,应该用RowPitch(每行字节数)乘以高度得到总数据长度。直接用DepthPitch会导致Span长度错误,甚至为空。

修复:
计算正确的总字节数:

// 总字节数 = 每行字节数 × 纹理高度
int totalBytes = (int)(mappedSubresource.RowPitch * desktopDesc.Height);
var span = new ReadOnlySpan<byte>(mappedSubresource.PData, totalBytes);

3. 未同步GPU异步操作

CopyResource是GPU异步操作,若在GPU完成复制前调用Map,会读取到未初始化的内存,表现为空数据。

修复:
添加GPU同步确保复制完成:

immediateContext->CopyResource(stagingResource, desktopTexture);

// 创建栅栏同步GPU操作
ID3D11Fence* fence = null;
device->CreateFence(0, (uint)FenceFlag.None, typeof(ID3D11Fence).GUID, (void**)&fence);
immediateContext->Signal(fence, 1);
// 等待GPU完成复制
fence->SetEventOnCompletion(1, IntPtr.Zero);

// 释放栅栏资源
fence->Release();

4. 未正确释放COM资源(潜在问题)

未释放desktopResource、stagingTexture等COM资源可能导致后续操作异常,操作完成后需手动释放:

// 在读取数据完成后执行
immediateContext->Unmap(stagingResource, 0);
desktopResource->Release();
desktopTexture->Release();
stagingTexture->Release();
stagingResource->Release();
outputDuplication->ReleaseFrame();

内容的提问来源于stack exchange,提问作者MakesYT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 03:13:23