SharpDX.WPF 渲染期间增加内存使用

SharpDX.WPF Increasing memory usage during rendering

我已经开始在 WPF 应用程序中使用 DirectX。我的第一步是使用简单的库: SharpdDX.WPF。基于示例,我实现了 WPF 控件绘制简单的线条。 SharpDX.WPF 使用 D3DImage 在 WPF 中渲染图像。 不幸的是,应用程序的内存一直在增加。

我实现了 class TestControlRenderer:D3D10。 顶点着色器初始化如下:

        var sizeInBytes = dataLength * sizeof(int) * 3;
        var bufferDescription = new BufferDescription(
            sizeInBytes,
            ResourceUsage.Dynamic,
            BindFlags.VertexBuffer,
            CpuAccessFlags.Write,
            ResourceOptionFlags.None);

        using (var stream = new DataStream(sizeInBytes, true, true))
        {
            stream.Position = 0;
            _graphDataVertexBuffer = new SharpDX.Direct3D10.Buffer(Device, stream, bufferDescription);
        }

        Device.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(_graphDataVertexBuffer, sizeof(int) * 3, 0));
        Device.InputAssembler.PrimitiveTopology = PrimitiveTopology.LineStrip;

然后使用着色器中使用的参数常量缓冲区:

_controlInfoConstantBuffer = new ConstantBuffer<ControlParamsShaderData>(Device);
        Device.VertexShader.SetConstantBuffer(0, _controlInfoConstantBuffer.Buffer);

要初始化动画重置方法是这样重写的:

        base.Reset(args);
        if (args.RenderSize.Width == 0) return;

        _drawArgs = args;
        InitVertexBuffer(dataLength);

        _controlInfoConstantBuffer.Value = new ControlParamsShaderData
        {
            SamplesInControl = dataLength,
            MinSignalDataY = -1500,
            MaxSignalDataY = 1500
        };

        Device.VertexShader.SetConstantBuffer(0, _controlInfoConstantBuffer.Buffer);

最后一步是RenderScene方法:

        public override void RenderScene(DrawEventArgs args)
    {
        if (args.RenderSize.Width == 0) return;

        Device.ClearRenderTargetView(RenderTargetView, Color.Transparent);

        using (var stream = _graphDataVertexBuffer.Map(MapMode.WriteDiscard, SharpDX.Direct3D10.MapFlags.None))
        {
            for (int i = 0; i < Data.Length; i++)
            {
                stream.Write(new Vector3(i, Data[i], 0));
            }
        }
        _graphDataVertexBuffer.Unmap();
        Device.Draw(Data.Length, 0);
    }

渲染由 DispatcherTimer 控制,其中 OnTickMethod 使用点坐标更新数组,然后调用 Render() 方法。

我的问题很简单,是内存泄漏还是在每次渲染迭代时产生的东西? 我不更改后备缓冲区或创建其他对象。只改变数据数组,将其更新到 GPU 和着色器处理它以显示。 我的情况是在一个屏幕上显示大约 30 个 wpf 控件宽度的 DirectX。控件带有简单但实时的动画。这样可以吗?

您很可能正在泄漏资源。您可以通过设置静态配置 属性

来查看
SharpDX.Configuration.EnableObjectTracking = true;

然后调用

SharpDX.Diagnostics.ObjectTracker.ReportActiveObjects()

在您的应用程序生命周期的不同时间点查看是否有任何泄漏(至少在 SharpDX 方面)。您可以编辑代码以确保处置这些对象。仅在调试时启用对象跟踪 - 这会影响性能。

SharpDX 曾经在终结器 运行 对象尚未被处置时释放 COM 对象(至少在版本 2.4.2 中如此),但后来禁用了它(他们在其中一个详细说明了原因变更日志,我忘了是哪一个)。

此外,DirectX requires that you release objects in the reverse order they were created - 这会造成难以调试的内存泄漏。所以当你的代码是

var device = new Devie(...);
var effect = new Effec(Device, byteCode);
technique = effect.GetTechniqueByName(techniqueName);
inputLayout = new InputLayout(Device, _technique.GetPassByIndex(0).Description.Signature, ...);

那么你的处置代码必须是

_inputLayout.Dispose();
_technique.Dispose();
_effect.Dispose();
_device.Dispose();