【问题标题】:Memory increase with SharpDX bitmap drawing使用 SharpDX 位图绘图增加内存
【发布时间】:2017-05-10 22:01:41
【问题描述】:

我对 DirectX 和 Direct2D 还很陌生。我正在尝试使用 SharpDx 卸载硬件上的工作,而不是消耗 CPU 进行持续渲染。

我有一个媒体基础管道。我实现了一个自定义渲染器。我的应用程序使用 C# 和 WPF。

我从管道中获取原始像素并将它们推送到正在更新图像控件的 WritableBitamps。显然,图像控件存在一个已知问题,它可以固定画笔。我的应用程序可以针对这个问题抛出内存异常。如果原始框架不大,则问题不明显。比方说 800x600 视频。

如果播放 1920 x 1080 的视频,我会遇到更多问题。

我尝试创建一个 BitmapSource 并更新后台缓冲区(以防止不断创建 bitamp),但这并没有帮助。在某些情况下,记忆会疯狂增长。到目前为止,我正在为每幅画创建新的 bitamp。我知道这是测试的临时解决方案。

所以现在我正在试验的是 SharpDx。我正在使用一个名为 D2DControl 的包装器,它包装了一个 D3DImage 和设置代码,并允许创建一个 WPF 控件,您可以将其插入到您的视图中(类似于 D3DImage。D2DControl 派生自 D3DImage)我知道有些人讨厌外部链接,但这里是链接以防有人感兴趣。

https://github.com/dalance/D2dControl/tree/master/D2dControl

这个包装器所做的是它隐藏了很多细节。它公开了一个允许绘图发生的 Render() 方法。

这就是我所拥有的。

public class MediaDisplayControl : D2dControl.D2dControl
{
    private Bitmap backBufferBmp;        
    public FrameRenderer Renderer { get; set; }

    public override void Render(RenderTarget target)
    {
        var sampleData = Renderer.Samples.FirstOrDefault();

        if (sampleData != null)
        {
            if (backBufferBmp == null)
                backBufferBmp = new Bitmap(target, new SharpDX.Size2(sampleData.Width, sampleData.Height), new BitmapProperties(target.PixelFormat));

            backBufferBmp.CopyFromMemory(sampleData.Pixels, sampleData.Stride);

            target.Transform = new RawMatrix3x2 { M11 = target.Size.Width / backBufferBmp.Size.Width, M22 = target.Size.Height / backBufferBmp.Size.Height };
            target.DrawBitmap(backBufferBmp, 1f, BitmapInterpolationMode.Linear);
        }
    }
}

我尝试了在每次渲染上创建新的 bitamp 或重复使用它的变体。在 1920x1080 视频帧上,内存一次跳跃 300mg,直到达到 1.2GB 并停止。

我正在缩放位图,因为 D3DImage 没有缩放位放大器。使用 Image 控件,您可以编写一个大的 bitamp,它会缩放到视图大小。使用此代码,如果图像大于容器,则图像会被裁剪。

无论如何,转换不会改变结果。 CopyFromMemory 和 DrawBitamp 的行为增加了内存。

所以我的问题是: 1)我在做什么有意义吗? 2) 我可以采取其他措施来防止内存问题吗?

感谢您花时间阅读本文。

【问题讨论】:

    标签: memory-leaks bitmap directx sharpdx hardware-acceleration


    【解决方案1】:

    我看到您尝试通过将Unmanaged memory 复制到Managed memory 并再次复制到Unmanaged memory 来解决您的任务。首先,你得到用于渲染的原始像素——这不是一个好主意,因为代码不能使用DirectX Video Acceleration 来加速解码——它会解码到 CPU 内存中。其次,在您的代码中有Bitmap backBufferBmp - 它是一个托管内存对象,您无法快速从内存中清除它,但您可以尝试GC.Collect Method ()。第三,在渲染过程中,系统内存中backBufferBmp的像素复制到WPF的显存中。因此,在您的解决方案中,三个存在许多瓶颈。我可以推荐尝试System.Windows.Interop.D3DImage - 它允许将Direct3DSurface9 附加到渲染进程WPF 而不从内存中复制,然后您可以使用Direct3DSurface9 作为使用DirectX Video Acceleration 的渲染目标。但是,它需要为 Media Foundation 管道编写一个新的自定义渲染器。

    因此,没有magic 代码行可以解决您的问题 - 您需要从头开始重写代码。

    问候。

    附:您可以通过链接找到使用System.Windows.Interop.D3DImage 的示例 - WPFViewerEVRDisplay

    【讨论】:

    • 感谢您提供详细信息!我看了你的项目。首先,干得好!这就是我在 D2DControl 中看到的。 API 使用 Texture2D 表面,它在内部附加到 D3DImage。表面未暴露,因此无法直接触摸后缓冲区。查看 SharpDX 代码库,似乎 Bitamp 对象使用指向内存的本机指针来获取像素。我不是 GC.Collect 的粉丝。如果重复调用它是非常昂贵的。我们的 API 中有一些旧代码,每 2 毫秒有一次 GC.Collect 调用,删除它使代码速度提高了 10 倍。
    • Bitamp 对象不是 System.Drawing.Bitamp。它是 SharpDX 定义的,应该是硬件支持的。至少我是这么认为的。我需要确认一下
    • 嗨,我想提醒你注意 SharpDX.Direct2D1.Bitmap 有很多重载 CopyFromMemory 函数。例如'public void CopyFromMemory(byte[] memory, int pitch);' public void CopyFromMemory(IntPtr pointer, int pitch); - 首先获取 C# 托管内存,另一个获取非托管内存上的指针。从您的代码backBufferBmp.CopyFromMemory(sampleData.Pixels, sampleData.Stride); 看来,sampleData.Pixelsbyte[] - 它是托管内存。如果它是真实的byte[] - 那么你有复制过程 - Unmanaged memory -> Managed memory -> Unmanaged memory
    【解决方案2】:

    更新:

    非常感谢@Evgeny Pereguda 的详细解答。它帮助我意识到我忽略的一些想法。我采取了在 Cli/C++ 中封装 Direct3D9 接口的路线。

    在他的示例项目中,他使用 ComImport 将 Direct3D9 拉入 C# 端。这需要一些关于 dll 本身的知识。

    根据 C# 端的 COM 文档,您不能部分拉入接口。它是全部或只是 Class Guida 和名称。在 Direct3D9 的情况下,有很多函数并且试图定义所有函数(因为我很可能使用整个类中的 1 个方法)是一种矫枉过正的做法。

    他的方法使用反射从dll中根据方法的地址拉入方法,这需要对方法地址进行硬编码。我选择使用头文件和 D3D9.lib 为我需要的 Direct3D9 类正确包装,因为我对硬编码的事情有点挑剔。

    我创建了一个完整的用户控件,可以插入到我们的应用程序中。

    感谢有关内存问题的指导。最好的方法是使用非托管内存,但我没有意识到我使用的是托管内存。切换有助于提高性能和管理的内存很多。

    SharpDx 很好,但是很多细节都被隐藏了,我希望有更多的控制权。

    截至目前,我将非托管像素写入我的管道并且内存运行正常。

    【讨论】:

      猜你喜欢
      • 2019-02-20
      • 2015-01-02
      • 2017-01-13
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多