Direct2D 导致 D3D 出现 LiveObjects 警告

问题描述 投票:0回答:1

我正在尝试使用 Direct2D 和 Direct3D 互操作性,如 Microsoft Docs 中所述 我正在使用 C# 和 Silk.Net ,所以我制作了这个封装了 D2D1 和 DWrite Logic 的类,渲染目标绑定到后台缓冲区。

    internal class Silk2DOverLay : IDisposable
{
    private bool _isDisposed;
    private bool _isDrawing;
    private D2D _d2D;
    private ComPtr<ID2D1Factory> _factory;

    private ComPtr<ID2D1RenderTarget> _renderTarget;

    private ComPtr<ID2D1SolidColorBrush> _mouseOverBrush;
    private ComPtr<ID2D1SolidColorBrush> _solidColorBrush;
    private ComPtr<ID2D1SolidColorBrush> _backColorBrush;

    private ComPtr<IDWriteTextFormat>[] _textFormats;

    public unsafe Silk2DOverLay()
    {
        _d2D = D2D.GetApi();

        var guid = ID2D1Factory.Guid;
        var options = new FactoryOptions { DebugLevel = DebugLevel.None };
        ID2D1Factory* factory;
        var ppFactory = (void**)&factory;

        SilkMarshal.ThrowHResult(
            _d2D.D2D1CreateFactory(FactoryType.SingleThreaded, ref guid, in options, ppFactory)
        );
        _factory = factory;
        factory->Release();
        factory = null;
        InitFont();
    }

    public unsafe void Dispose()
    {
        if (!_isDisposed)
        {
            if (_isDrawing)
                End();

            for (var i = 0; i < _textFormats.Length; i++)
                Disposer.Dispose(ref _textFormats[i]);

            if (_renderTarget.Handle != null)
            {
                ulong tag1 = 0;
                ulong tag2 = 0;
                _renderTarget.Flush(&tag1, &tag2);
                _renderTarget.Dispose();
            }
            if (_solidColorBrush.Handle != null)
                _solidColorBrush.Dispose();
            if (_backColorBrush.Handle != null)
                _backColorBrush.Dispose();
            if (_mouseOverBrush.Handle != null)
                _mouseOverBrush.Dispose();

            Disposer.Dispose(ref _factory);
            Disposer.Dispose(ref _d2D);
            GC.SuppressFinalize(this);
            _isDisposed = true;
            Debug.WriteLine("2DDevise Disposed");

        }
    }
    public void Release()
    {
        Disposer.Dispose(ref _renderTarget);
        Disposer.Dispose(ref _solidColorBrush);
        Disposer.Dispose(ref _backColorBrush);
        Disposer.Dispose(ref _mouseOverBrush);
    }
    private unsafe void InitFont()
    {
        // Dispose of existing text formats
        if (_textFormats != null)
            for (var i = 0; i < _textFormats.Length; i++)
                Disposer.Dispose(ref _textFormats[i]);

        ComPtr<IDWriteFactory6> dWriteFactory;
        var dWrite = DWrite.GetApi();
        SilkMarshal.ThrowHResult(
            dWrite.DWriteCreateFactory(Silk.NET.DirectWrite.FactoryType.Isolated, out dWriteFactory)
        );

        var fontManager = new SoulsFontManager((IntPtr)dWriteFactory.Handle);
        var fontCollection = (IDWriteFontCollection*)fontManager?.GetFontCollection();

        // Define font settings for each text format
        var fontSettings = new[]
        {
            new
            {
                FontName = "ViewPortIcons",
                FontSize = 23f,
                Weight = FontWeight.Normal,
            },
            new
            {
                FontName = "Jura",
                FontSize = 20f,
                Weight = FontWeight.Normal,
            },
            new
            {
                FontName = "Jura",
                FontSize = 15f,
                Weight = FontWeight.Normal,
            },
        };

        // Initialize text formats array
        _textFormats = new ComPtr<IDWriteTextFormat>[fontSettings.Length];

        for (var i = 0; i < fontSettings.Length; i++)
        {
            var setting = fontSettings[i];
            _textFormats[i] = CreateTextFormat(
                dWriteFactory,
                setting.FontName,
                fontCollection,
                "en-US",
                setting.FontSize,
                FontWeight.Normal,
                FontStyle.Normal
            );
            _textFormats[i].SetTextAlignment(TextAlignment.Center);
            _textFormats[i].SetParagraphAlignment(ParagraphAlignment.Center);
        }

        dWrite.Dispose();
        dWriteFactory.Dispose();
        fontManager?.Dispose();
    }

    // Helper method to create a text format
    private unsafe ComPtr<IDWriteTextFormat> CreateTextFormat(
        ComPtr<IDWriteFactory6> factory,
        string fontName,
        IDWriteFontCollection* fontCollection,
        string localeName,
        float fontSize,
        FontWeight fontWeight,
        FontStyle fontStyle
    )
    {
        ComPtr<IDWriteTextFormat> textFormat = default;

        fixed (char* fontname = fontName)
        fixed (char* localname = localeName)
        {
            SilkMarshal.ThrowHResult(
                factory.CreateTextFormat(
                    fontname,
                    fontCollection,
                    fontWeight,
                    fontStyle,
                    FontStretch.Normal,
                    fontSize,
                    localname,
                    textFormat.GetAddressOf()
                )
            );
        }

        return textFormat;
    }

   

    /// <summary>
    ///     Update all resources
    /// </summary>
    /// <param name="backBuffer">BackBuffer</param>
    internal unsafe void UpdateResources(ID3D11Texture2D* backBuffer)
    {
        var d2dSurface = backBuffer->QueryInterface<IDXGISurface>();

        var props = new RenderTargetProperties(
            RenderTargetType.Default,
            new PixelFormat(Format.FormatUnknown, AlphaMode.Premultiplied),
            96,
            96
        );
        ID2D1RenderTarget* pRenderTarget = null;
        SilkMarshal.ThrowHResult(
            _factory.CreateDxgiSurfaceRenderTarget(d2dSurface.Handle, props, &pRenderTarget)
        );
        _renderTarget = pRenderTarget;
        if (pRenderTarget != null)
        {
            pRenderTarget->Release();
            pRenderTarget = null;
        }

        d2dSurface.Dispose();
        CreateFontBrush();
    }

    internal unsafe void CreateFontBrush()
    {
        Disposer.Dispose(ref _solidColorBrush);
        Disposer.Dispose(ref _backColorBrush);
        Disposer.Dispose(ref _mouseOverBrush);

        ID2D1SolidColorBrush* brush = null;
        var fontcolor = SilkColors.White.D3DColor;
        var props = new BrushProperties { Opacity = 1f, Transform = Matrix3X2<float>.Identity };
        SilkMarshal.ThrowHResult(_renderTarget.CreateSolidColorBrush(&fontcolor, props, &brush));
        _solidColorBrush = brush;

        fontcolor = SilkColors.Black.D3DColor;
        props.Opacity = 0.2f;
        SilkMarshal.ThrowHResult(_renderTarget.CreateSolidColorBrush(&fontcolor, props, &brush));
        _backColorBrush = brush;
        props.Opacity = 0.3f;
        fontcolor = SilkColors.Snow.D3DColor;
        SilkMarshal.ThrowHResult(_renderTarget.CreateSolidColorBrush(&fontcolor, props, &brush));
        _mouseOverBrush = brush;
        if (brush != null)
        {
            brush->Release();
            brush = null;
        }
    }

    /// <summary>
    ///     Draw 2D Block
    /// </summary>
    public unsafe void Draw2D(D2DBlock block)
    {
        if (_textFormats.Length < 3)
            throw new InvalidOperationException();

        IDWriteTextFormat* tFormat = null;

        if (block.TextFormat < _textFormats.Length)
            tFormat = _textFormats[block.TextFormat];
        else
            tFormat = _textFormats[2];

        var textFormat = (Silk.NET.Direct2D.IDWriteTextFormat*)tFormat;

        ID2D1Brush* brush2 = default;
        if (block.IsMouseOver)
            brush2 = (ID2D1Brush*)_mouseOverBrush.Handle;
        else
            brush2 = (ID2D1Brush*)_backColorBrush.Handle;

        if (block.HasBackground)
            _renderTarget.FillEllipse(block.BackGroundEllipse, brush2);

        var brush = (ID2D1Brush*)_solidColorBrush.Handle;
        fixed (char* pText = block.ContentText)
        {
            _renderTarget.DrawTextA(
                pText,
                (uint)block.ContentText.Length,
                textFormat,
                block.BoundingBox,
                brush,
                DrawTextOptions.EnableColorFont,
                DwriteMeasuringMode.Natural
            );
        }
    }

    /// <summary>
    ///     Begin a 2D drawing session
    /// </summary>
    public void Begin()
    {
        _isDrawing = true;
        _renderTarget.BeginDraw();
    }

    /// <summary>
    ///     End drawing session
    /// </summary>
    public unsafe void End()
    {
        ulong tag1 = 0;
        ulong tag2 = 0;
        SilkMarshal.ThrowHResult(_renderTarget.EndDraw(&tag1, &tag2));
        _isDrawing = false;
    }
}

问题是关闭应用程序时,我收到许多 D3D11Device Live Objects 警告,但我确保所有 D3D 资源都得到正确处理。 当使用

ReportLiveObjects()
时,活动对象都是 D3D11 Recourses 。 但如果我不初始化
Silk2DOverLay
实例以防止其被使用,警告就会消失

 public SilkGraphicsDevice(ISilkView viewport)
 {
     _viewport = viewport;
     InitializeApis();
     Initialize();
     _silk2DOverLay = new Silk2DOverLay();//if i removed this line 
     OnResize();
     CreateFence();
 }

这就是为什么我没有遇到问题,如果问题出在我的处理逻辑上,无论

Silk2DOverLay
如何,都会出现警告,有人可以帮助我吗?

Device和交换链的dispose逻辑 公共无效处置() {

  _silk2DOverLay.Release();
  Disposer.Dispose(ref _backBufferView);
  Disposer.Dispose(ref _factory);
  Disposer.Dispose(ref _swapChain);
  Disposer.Dispose(ref _depthBufferView);
  Disposer.Dispose(ref _deviceContext);
  Disposer.Dispose(ref _threadShield);

  Disposer.Dispose(ref _d3d11);
  Disposer.Dispose(ref _dxgi);
  Disposer.Dispose(ref _fence);
  Disposer.Dispose(ref _device);
  Disposer.Dispose(ref _silk2DOverLay);
  GC.SuppressFinalize(this);
 

} 所有对象都将在此类的窗口关闭事件中被处理

public static class Disposer
{
    public static void Dispose<T>(ref T disposable)
        where T : class?, IDisposable?
    {
        if (disposable != null)
        {
            disposable.Dispose();
            disposable = null;
        }
    }

    public static unsafe void Dispose<T>(ref ComPtr<T> disposable)
        where T : unmanaged, IComVtbl<T>
    {
        if (disposable.Handle != null)
        {
            disposable.Dispose();
            disposable = null;
        }
    }
}

输出警告和 ReportLiveObjects() 输出此处

c# directx-11 direct2d
1个回答
0
投票

看起来您遇到了与 D3D11 资源相关的

LiveObjects
警告,即使您确保正确处置也是如此。该问题可能与 Direct3D 和 Direct2D 对象与您的
Silk2DOverLay
实例关联时的管理方式有关。创建和使用
Silk2DOverLay
实例时,它可能会创建未正确清理的引用,这会导致退出应用程序时出现 D3D11 活动对象警告。

这里有一些需要检查和尝试的事情:

  1. 验证释放顺序:确保在处置

    Silk2DOverLay
    _device
    _swapChain
    等主要资源之前释放
    _d3d11
    资源(以及与其关联的D3D资源)。释放这些资源的时间可能会影响清理过程。

  2. 使用显式清理:不要依赖自动处置,而是按照创建和处置的顺序手动释放或取消每个资源。这有助于确保不存在对 D3D 对象的延迟引用。

  3. 检查关联 ComPtrs 的处置:确保类中的

    ComPtr
    对象(如
    _renderTarget
    _factory
    )在处置时正确释放并清空。有时,丢失或错误处理
    ComPtr
    可能会导致这些警告。

  4. 跟踪资源所有权:如果

    Silk2DOverLay
    保留 D3D 对象(如
    ID2D1RenderTarget
    ID3D11Texture2D
    ),请仔细检查是否已清除对这些对象的所有引用。如果任何对象被其他对象隐式保留或在释放后未显式清空,则可能会导致活动对象警告。

  5. 在关键点

    调用
    ReportLiveObjects:处置资源后,使用
    ReportLiveObjects
    确保没有D3D11对象仍然存活。这将帮助您查明任何可能未正确释放的资源。

  6. 调查 Silk.NET 清理:由于您使用的是 Silk.NET,请确保其内部清理机制(例如自动处置

    ComPtr
    对象)按预期工作。在某些情况下,Silk.NET 可能需要关于何时以及如何清理某些对象的明确指示。

通过关注资源处置的时间和完整性并检查对象的跟踪和释放方式,您应该能够识别活动对象持续存在的位置并纠正问题。

© www.soinside.com 2019 - 2024. All rights reserved.