DirectX中保存多重采样纹理为图片时显示空白的问题
问题修复:MSAA模式下保存交换链纹理为空白的解决办法
我先直接点明核心问题——这是一个低级拼写错误,启用DirectX调试层后就能立刻发现问题所在。不过你的SaveContentsToImage代码框架本身很有参考价值,适合需要导出多重采样纹理的开发者,所以我整理了修复方案:
错误根源分析
你的代码里已经正确用ResolveSubresource把MSAA纹理解析到了非多重采样的intermediateTexture,但后续执行CopyResource时,错误地把原始的多重采样backBufferTexture作为源,而不是用解析后的intermediateTexture!Direct3D不允许直接将MSAA纹理复制到staging纹理,这就导致最终读取到的是空白数据。
修复后的完整代码
private void SaveContentsToImage() { D3D11.Texture2D backBufferTexture = _swapChain.GetBackBuffer<D3D11.Texture2D>(0); // 解析MSAA纹理到非多重采样的中间纹理 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); // 创建用于CPU读取的暂存纹理 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); // 关键修复:使用解析后的intermediateTexture作为复制源 _d3DDeviceContext.CopyResource(intermediateTexture, 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."); // 补充:释放资源避免内存泄漏 intermediateTexture.Dispose(); copyTexture.Dispose(); wicBitmap.Dispose(); bitmap.Dispose(); dataStream.Dispose(); }
额外建议:启用DirectX调试层
开启调试层能帮你快速捕获这类资源操作错误,在创建D3D设备时添加调试标志即可:
var deviceFlags = D3D11.DeviceFlags.Debug; using (var device = new D3D11.Device(D3D11.DriverType.Hardware, deviceFlags)) { // 设备初始化逻辑 }
调试层会在输出窗口打印详细的错误信息,比如尝试复制MSAA纹理到staging纹理的非法操作,能帮你立刻定位问题。
内容的提问来源于stack exchange,提问作者Reign of Error
相关产品推荐
相关产品推荐

