如何执行昂贵的渲染
问题内容:
在许多情况下,渲染需要大量的计算能力。因此,可能会发生由于UI需要等待渲染完成而跳过帧的情况。
我想知道如何实现 异步 (即孤立)渲染或绘画。
像这样compute
的函数不是一个选项,因为SendPort
仅适用于原始类型,绘画需要使用PaintingContext
or Canvas
。
有些Flutter插件需要大量渲染。因此,我以为我可以在video_player
插件中找到答案,但是它使用Texture
,即 在Dart 中不渲染。
我想知道是否有任何与此相关的成语或示例实现。
我想知道如何实现渲染,可以看一下FlareActor
。事实证明,他们像我一样处理绘画。现在我想知道为什么我遇到瓶颈而Flare却没有。有优化绘画的指南吗?
问题答案:
我通过将所有需要的像素写入BMP
文件格式来解决此问题,然后使用它Canvas.drawImage
代替,因为Flutter画布无法处理许多Canvas
操作:
解
dart:ui具有将像素Image轻松转换为的功能:decodeImageFromPixels
示例实施
性能问题
在当前master频道中不起作用
当我创建此答案时,我根本不知道这一点,这就是为什么我写了“ Alternative ”部分。
另类
感谢@pslinkBMP在我写完我自己的编码失败后提醒我PNG。
我以前曾研究过它,但是我认为如果没有足够的文档,它看起来会很复杂。现在,我发现这篇不错的文章 解释了必要的BMP标头,并通过从“ BMP文件格式 ”维基百科文章中复制了示例2,实现了32位BGRA(ARGB,但BGRA是默认掩码的顺序)。我浏览了所有资料,但找不到此示例的原始资料。维基百科文章的作者也许是自己写的。
结果
使用Canvas.drawImage我的999x999像素从转换为图像BMP字节列表中,我得到一个GPU最大的9.9 ms/frame和UI最大的7.1 ms/frame,这是真棒!
| ms/frame | Before (Canvas.drawRect) | After (Canvas.drawImage) |
|-----------|---------------------------|--------------------------|
| GPU max | 1824.7 | 9.9 |
| UI max | 2362.7 | 7.1 |
结论
像这样的Canvas操作Canvas.drawRect并不意味着那样使用。
使用说明
首先,这很简单,但是,您需要正确填充字节列表,否则,您将得到一个错误,即您的数据格式不正确并且看不到结果,这可能会令人沮丧。
由于无法使用绘画调用中的操作,因此需要在绘制之前准备图像async。
在代码中,您需要使用Codec
来将字节列表转换为图像。
final list = [
0x42, 0x4d, // 'B', 'M'
...];
// make sure that you either know the file size, data size and data offset beforehand
// or that you edit these bytes afterwards
final Uint8List bytes = Uint8List.fromList(list);
final Codec codec = await instantiateImageCodec(bytes));
final Image image = (await codec.getNextFrame()).image;
您需要将此图像传递到绘图小部件,例如使用FutureBuilder。现在,您可以Canvas.drawImage
在绘图调用中使用。