C# 保存到图像时,多采样纹理为空(DirectX)

C# 保存到图像时,多采样纹理为空(DirectX),c#,directx,direct3d,sharpdx,multisampling,C#,Directx,Direct3d,Sharpdx,Multisampling,更新:这个问题被证明是一个愚蠢的打字错误(参见答案),在我启用它之后,DirectX调试层清楚地识别了它。但是,我将这个问题留给大家,因为我认为SaveContentsToImage代码可能是其他希望导出多采样纹理的人的有用参考 我正在尝试将多采样纹理(从swapchain)的内容保存到图像中。我正在使用功能级别为11.0的Direct3D。我有一段代码(基于和),当swapchain初始化时,SampleDescription计数设置为1(无多重采样),但将计数设置为2、4等,以启用MSAA

更新:这个问题被证明是一个愚蠢的打字错误(参见答案),在我启用它之后,DirectX调试层清楚地识别了它。但是,我将这个问题留给大家,因为我认为
SaveContentsToImage
代码可能是其他希望导出多采样纹理的人的有用参考


我正在尝试将多采样纹理(从swapchain)的内容保存到图像中。我正在使用功能级别为11.0的Direct3D。我有一段代码(基于和),当swapchain初始化时,SampleDescription计数设置为1(无多重采样),但将计数设置为2、4等,以启用MSAA会导致空白图像

“保存到图像”函数用于将swapchain中的多采样纹理解析为非多采样中间纹理,然后用于将中间纹理复制到启用CPU读取访问的暂存纹理中。代码如下:

private void SaveContentsToImage()
{
    // TODO breaks when using MSAA.

    D3D11.Texture2D backBufferTexture = _swapChain.GetBackBuffer<D3D11.Texture2D>(0);

    // Intermediate texture used to resolve source using MSAA (unnecessary if source sample count is 1).
    D3D11.Texture2DDescription intermediateTextureDesc = backBufferTexture.Description;
    intermediateTextureDesc.SampleDescription = new SampleDescription(1, 0);
    intermediateTextureDesc.Usage = D3D11.ResourceUsage.Default;

    D3D11.Texture2D intermediateTexture = new D3D11.Texture2D(_d3dDevice, intermediateTextureDesc);

    _d3DDeviceContext.ResolveSubresource(backBufferTexture, 0, intermediateTexture, 0, backBufferTexture.Description.Format);
    //_d3DDeviceContext.ResolveSubresource(_renderTargetView.Resource, 0, intermediateTexture, 0, backBufferTexture.Description.Format); // Works identically to above.

    D3D11.Texture2DDescription copyDesc = backBufferTexture.Description;
    copyDesc.SampleDescription = new SampleDescription(1, 0);
    copyDesc.Usage = D3D11.ResourceUsage.Staging;
    copyDesc.BindFlags = D3D11.BindFlags.None;
    copyDesc.CpuAccessFlags = D3D11.CpuAccessFlags.Read;

    D3D11.Texture2D copyTexture = new D3D11.Texture2D(_d3dDevice, copyDesc);

    _d3DDeviceContext.CopyResource(backBufferTexture, copyTexture);

    DataStream dataStream;
    var dataBox = _d3DDeviceContext.MapSubresource(copyTexture, 0, 0, D3D11.MapMode.Read, D3D11.MapFlags.None, out dataStream);

    DataRectangle dataRectangle = new DataRectangle
    {
        DataPointer = dataStream.DataPointer,
        Pitch = dataBox.RowPitch
    };

    Bitmap wicBitmap = new Bitmap(_wicFactory, copyTexture.Description.Width, copyTexture.Description.Height, PixelFormat.Format32bppBGRA, dataRectangle);

    byte[] pixelData = new byte[copyTexture.Description.Width * copyTexture.Description.Height * 4];
    wicBitmap.CopyPixels(pixelData, copyTexture.Description.Width * 4);
    System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(copyTexture.Description.Width, copyTexture.Description.Height);
    BitmapData bitmapData = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, copyTexture.Description.Width, copyTexture.Description.Height), ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
    Marshal.Copy(pixelData, 0, bitmapData.Scan0, pixelData.Length);
    bitmap.UnlockBits(bitmapData);

    bitmap.Save("test.png");

    Console.WriteLine("Saved image.");
}

SampleCount
是一个整数常量,设置为1、2、4等。如果设置为1,
SaveContentsToImage()
将生成与屏幕渲染内容匹配的图像;如果是更高的值,则生成的图像为空。

我最终能够安装使用DirectX调试层所需的功能(除了图形工具可选功能外,还必须安装并启用开发人员模式)

一旦我能够使用调试层,我将其设置为在除信息之外的所有消息严重性级别上中断:

D3D11.InfoQueue infoQueue = _d3dDevice.QueryInterface<D3D11.InfoQueue>();

infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Corruption, true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Error, true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Message, true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Warning, true);
D3D11.InfoQueue InfoQueue=\u d3dDevice.QueryInterface();
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Corruption,true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Error,true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Message,true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Warning,true);
调用
SaveContentsToImage
中的
CopyResource
时出错:

D3D11错误:ID3D11DeviceContext::CopyResource:无法调用CopyResource,因为源资源多采样(采样数:4,质量:0)和目标资源多采样(采样数:1,质量:0)之间不匹配。[RESOURCE#u操纵错误#286:COPYRESOURCE_INVALIDSOURCESTATE]


在这一点上,我觉得自己很傻。
CopyResource
调用是
\u d3DDeviceContext.CopyResource(BackufferTexture,copyTexture)
,而它本应是
\u d3DDeviceContext.CopyResource(intermediateTexture,copyTexture)
。显然,在添加中间纹理以支持多重采样后,我忽略了更新此行。

是否启用了调试设备并查找了输出消息?假设您指的是调试层,则需要安装“图形工具”Windows可选功能(请参阅)。由于我公司的安全政策,这需要IT干预。我在两天前提交了一张罚单,并打算在我能够启用调试层时启用它。这确实是找到原因的第一步。这很公平。一旦能够启用调试层并检查其输出,我将更新问题。
D3D11.InfoQueue infoQueue = _d3dDevice.QueryInterface<D3D11.InfoQueue>();

infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Corruption, true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Error, true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Message, true);
infoQueue.SetBreakOnSeverity(D3D11.MessageSeverity.Warning, true);