正确的方法绘制非托管位图到屏幕

时间:2016-10-01 16:19:04

标签: c# xaml user-interface bitmap uwp

我正忙着创建一个xaml视图,用于使用Canvas后台Brush从非托管代码到屏幕绘制位图。有几件事我不确定(特别是因为文档很少/缺少)。

我正在使用SkiaSharp进行绘图,因此必须可以在非托管内存中访问内存块 - 我希望避免来回复制。

我找到了几种方法可以做到这一点,但我不确定框架的工作原理,以了解我是否做得对。第一种方法是使用byte[]WriteableBitmap

int width, height, length = ...;

// create the bits (once off)
byte[] pixels = new byte[length];
GCHandle buff = GCHandle.Alloc(pixels, GCHandleType.Pinned);
WriteableBitmap bitmap = new WriteableBitmap(width, height);
this.Background = new ImageBrush { ImageSource = bitmap };

// draw (in a game loop)
DrawUsingSkiaSharp(buff.AddrOfPinnedObject());

// update the UI
var stream = bitmap.PixelBuffer.AsStream();
stream.Seek(0, SeekOrigin.Begin);
stream.Write(pixels, 0, pixels.Length);
bitmap.Invalidate();

这很好用,我每帧只复制一次。此外,我可以绘制到相同的图像,并且位图充当双缓冲区。但是,bitmap.Invalidate导致第二次复制到屏幕上吗?

我发现我也可以使用SoftwareBitmap

// create
SoftwareBitmap bitmap = new SoftwareBitmap(
    BitmapPixelFormat.Bgra8, 
    width, height, 
    BitmapAlphaMode.Premultiplied);

// draw
using (var buffer = bitmap.LockBuffer(BitmapBufferAccessMode.ReadWrite))
using (var bufferRef = buffer.CreateReference())
{
    byte* b;
    uint capacity;
    ((IMemoryBufferByteAccess)bufferRef).GetBuffer(out b, out capacity);
    DrawUsingSkiaSharp(b);
}

// update
var source = new SoftwareBitmapSource();
this.Background = new ImageBrush { };
var action = source.SetBitmapAsync(bitmap);
action.Completed = (asyncInfo, asyncStatus) {
    ((ImageBrush)this.Background).ImageSource = source;
};

但是一旦我将位图分配给画笔,我就无法再次使用它(LockBuffer抛出)。解决这个问题的方法是使用第二个位图并将其复制到该位图。但这是否比WriteableBitmap有所改善 - 特别是我现在必须处理异步复杂性? SetBitmapAsync真正做了什么,为什么它是异步的?来源不能只读它 - 或者这里也有副本吗?

是否有第三种更好的方法,我应该使用其中一种,还是有不同的方法来做到这一点?就像没有使用画笔并直接绘制到Canvas(或者是否有更好的控制)

此外,使用游戏循环绘制时使用SoftwareBitmapSoftwareBitmapSource的正确方法是什么?

这么多选项,没有文档! :)

0 个答案:

没有答案