如何共享 WriteableBitmap 后台缓冲区以与 Direct2D 渲染一起使用?

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

我使用 WriteableBitmap 作为在 WPF 窗口中渲染和显示内容的快速方法,然后导出为媒体(重用相同的渲染管道)。

我可以绘制图像、基本形状,执行操作图像字节的常见操作(调整大小、裁剪、翻转、更改角度、不透明度等)。与此问题无关。

我的渲染管道只是获取 WriteableBitmap 后台缓冲区 (nint/IntPtr) 及其一些参数(大小、比例、偏移量等),并使用 SharpDX 来绘制文本,如下所示:

public override void RenderAt(nint canvas, int canvasStride, int canvasWidth, int canvasHeight, 
    double horizontalScale, double verticalScale, int leftOffset, int topOffset, 
    int rightOffset, int bottomOffset) 
{
    using (var factory = new SharpDX.Direct2D1.Factory(FactoryType.MultiThreaded))
    using (var writeFactory = new SharpDX.DirectWrite.Factory(SharpDX.DirectWrite.FactoryType.Shared))
    using (var textFormat = new TextFormat(writeFactory, "Segoe UI", 20))
    using (var bitmap = new SharpDX.WIC.Bitmap(new ImagingFactory(), canvasWidth, canvasHeight, SharpDX.WIC.PixelFormat.Format32bppPBGRA, SharpDX.WIC.BitmapCreateCacheOption.CacheOnLoad))
    using (var renderTarget = new WicRenderTarget(factory, bitmap, new RenderTargetProperties()))
    {
        //Create a SharpDX Bitmap as the backbuffer.
        var backBufferBitmap = new SharpDX.Direct2D1.Bitmap(renderTarget, new Size2(canvasWidth, canvasHeight), new SharpDX.Direct2D1.BitmapProperties(renderTarget.PixelFormat));
        backBufferBitmap.CopyFromMemory(canvas, canvasStride);

        //Render the text and other content to the backbuffer.
        renderTarget.BeginDraw();
        renderTarget.Transform = Matrix3x2.Scaling((float)horizontalScale, (float)verticalScale) * Matrix3x2.Translation(leftOffset, topOffset);
        renderTarget.DrawBitmap(backBufferBitmap, 1f, BitmapInterpolationMode.Linear);

        var text = "Example";

        //Backdrop.
        using (var brush = new SharpDX.Direct2D1.SolidColorBrush(renderTarget, new RawColor4(0,0,0,1)))
            renderTarget.FillRectangle(new RawRectangleF(0, 0, canvasWidth, canvasHeight / 4), brush);

        //Text.
        using (var brush = new SharpDX.Direct2D1.SolidColorBrush(renderTarget, new RawColor4(1,1,1,1)))
            renderTarget.DrawText(text, textFormat, new RectangleF(0, 0, Width, Height), brush);

        renderTarget.EndDraw();

        bitmap.CopyPixels(new RawBox(0, 0, canvasWidth, canvasHeight), canvasStride, new DataPointer(canvas, canvasStride * canvasHeight));
    }
}

我想知道是否可以直接绘制到后台缓冲区,而不必进行这么多复制操作,因为现在我已经做了两个副本。

c# direct2d sharpdx wic
1个回答
0
投票

WPF 的 WriteableBitmap 已经封装了 WIC Bitmap ,因此代码的性能可能会比您想象的得到改善,但遗憾的是它没有公开。

您可以使用如下代码来访问它:

var writeableBitmap = new WriteableBitmap(200, 200, 96, 96, PixelFormats.Bgr32, null); // create some writeable bitmap

// get its internal COM reference
var prop = writeableBitmap.GetType().GetProperty("WicSourceHandle", BindingFlags.NonPublic | BindingFlags.Instance);
var handle = (SafeHandleZeroOrMinusOneIsInvalid)prop.GetValue(writeableBitmap, null);

using (var bitmap = new SharpDX.WIC.Bitmap(handle.DangerousGetHandle())) // we're already walking on the dangerous edge anyway
{
    etc...
    // EndDraw does Lock+Unlock
}

注1:WPF现在已经相当冻结了,所以我认为使用这个内部结构不会有很大的风险,但这显然取决于你。

注 2:处理 WIC 位图就是在 CPU 上工作。如果您想要更好的性能,您可以使用驻留在 GPU 上并可以利用 GPU 能力的 Direct2D 位图。可能需要进行重要的更改。

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