и я использую C# с Silk.Net, поэтому я создал этот класс, который инкапсулирует логику D2D1 и DWrite, цель рендеринга привязана к задний буфер .
Код: Выделить всё
internal class Silk2DOverLay : IDisposable
{
private bool _isDisposed;
private bool _isDrawing;
private D2D _d2D;
private ComPtr _factory;
private ComPtr _renderTarget;
private ComPtr _mouseOverBrush;
private ComPtr _solidColorBrush;
private ComPtr _backColorBrush;
private ComPtr[] _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 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[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 CreateTextFormat(
ComPtr factory,
string fontName,
IDWriteFontCollection* fontCollection,
string localeName,
float fontSize,
FontWeight fontWeight,
FontStyle fontStyle
)
{
ComPtr 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;
}
///
/// Update all resources
///
///
BackBuffer
internal unsafe void UpdateResources(ID3D11Texture2D* backBuffer)
{
var d2dSurface = backBuffer->QueryInterface();
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.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;
}
}
///
/// Draw 2D Block
///
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
);
}
}
///
/// Begin a 2D drawing session
///
public void Begin()
{
_isDrawing = true;
_renderTarget.BeginDraw();
}
///
/// End drawing session
///
public unsafe void End()
{
ulong tag1 = 0;
ulong tag2 = 0;
SilkMarshal.ThrowHResult(_renderTarget.EndDraw(&tag1, &tag2));
_isDrawing = false;
}
}
И при использовании ReportLiveObjects()
code> все живые объекты — это ресурсы D3D11.
но если я не инициализирую экземпляр Silk2DOverLay, предотвращая его использование, предупреждения исчезнут
Код: Выделить всё
public SilkGraphicsDevice(ISilkView viewport)
{
_viewport = viewport;
InitializeApis();
Initialize();
_silk2DOverLay = new Silk2DOverLay();//if i removed this line
OnResize();
CreateFence();
}
логика удаления устройства и цепочки обмена
public void 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(ref T disposable)
where T : class?, IDisposable?
{
if (disposable != null)
{
disposable.Dispose();
disposable = null;
}
}
public static unsafe void Dispose(ref ComPtr disposable)
where T : unmanaged, IComVtbl
{
if (disposable.Handle != null)
{
disposable.Dispose();
disposable = null;
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... s-with-d3d