我正忙着创建一个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
(或者是否有更好的控制)
此外,使用游戏循环绘制时使用SoftwareBitmap
和SoftwareBitmapSource
的正确方法是什么?
这么多选项,没有文档! :)