文档章节

Skia深入分析2——skia渲染架构

jxt1234
 jxt1234
发布于 2015/10/15 18:06
字数 1515
阅读 121
收藏 0
一、渲染层级
从渲染流程上分,Skia可分为如下三个层级:
1、指令层:SkPicture、SkDeferredCanvas->SkCanvas
这一层决定需要执行哪些绘图操作,绘图操作的预变换矩阵,当前裁剪区域,绘图操作产生在哪些layer上,Layer的生成与合并。
2、解析层:SkBitmapDevice->SkDraw->SkScan、SkDraw1Glyph::Proc
这一层决定绘制方式,完成坐标变换,解析出需要绘制的形体(点/线/规整矩形)并做好抗锯齿处理,进行相关资源解析并设置好Shader。
3、渲染层:SkBlitter->SkBlitRow::Proc、SkShader::shadeSpan等
这一层进行采样(如果需要),产生实际的绘制效果,完成颜色格式适配,进行透明度混合和抖动处理(如果需要)。



二、主要类介绍
1、SkCanvas
这是复杂度超出想像的一个类。
(1)API设计
a、创建:
在Android中,主要的创建方法是由SkBitmap创建SkCanvas:
explicit SkCanvas(const SkBitmap& bitmap);
这个方法是由bitmap创建一个SkBitmapDevice,再将这个SkBitmapDevice设定为SkCanvas的渲染目标。


5.0之后提供了一个快捷方法创建SkCanvas:
static SkCanvas* NewRasterDirect(const SkImageInfo&, void*, size_t);
这样Android的GraphicBuffer就不需要建一个SkBitmap和它关联了,可以解除SkBitmap类和android runtime的关系(虽然如此,目前Android5.0上,还是按建SkBitmap的方法去关联GraphicBuffer)。


5.0之后引入的离屏渲染:
static SkCanvas* NewRaster(const SkImageInfo&);
创建一个SkCanvas,绘制的内容需要通过readPixels去读取,仍然是CPU绘图的方式。(个人觉得这个是转入GPU硬件加速的一个比较方便的接口,不知道出于什么考虑还是用CPU绘图。)


b、状态:
矩阵状态:
矩阵决定当前绘制的几何变换
rotate、skew、scale、translate、concat
裁剪状态:
裁剪决定当前绘制的生效范围
clipRect、clipRRect、clipPath、clipRegion
保存与恢复:
save、saveLayer、saveLayerAlpha、restore
c、渲染:
大部分渲染的API都可由这三个组合而成:
drawRect(矩形/图像绘制)、drawPath(不规则图形图像绘制)和drawText(文本绘制)
d、像素的读取与写入
readPixels、writePixels
这两个API主要由device实现,考虑到不同绘图设备的异质性。


(2)MCRec状态栈
fMCStack是存储的全部状态集,fMCRec则是当前的状态。
在 save saveLayer saveLayerAlpha 时,会新建一个MCRec,在restore时,销毁栈顶的MCRec。
(代码见:SkCanvas.cpp internalSave函数,通过这段代码可以了解一下new的各种用法~。)
每个状态包括如下信息:
class SkCanvas::MCRec {
public:
    int             fFlags;//保存的状态标识(是否保存矩阵/裁剪/图层)
    SkMatrix*       fMatrix;//矩阵指针,若这个状态有独立矩阵,则指向内存(fMatrixStorage),否则用上一个MCRec的fMatrix
    SkRasterClip*   fRasterClip;//裁剪区域,若这个状态有独立裁剪区域,则指向内存(fRasterClip),否则继承上一个的。
    SkDrawFilter*   fFilter;
    DeviceCM* fLayer;//这个状态所拥有的layer(需要在此MCRec销毁时回收)
    DeviceCM* fTopLayer;//这个状态下,所需要绘制的Layer链表。(这些Layer不一定属于此状态)
    ......
};
DeviceCM:图层链表,包装一个SkBaseDevice,附加一个位置偏移变化的矩阵(在saveLayer时指定的坐标)。


(3)两重循环绘制
研究Skia的人,一般来说都会被一开始的两重循环弄晕一会,比如drawRect的代码:


    LOOPER_BEGIN(paint, SkDrawFilter::kRect_Type, bounds)


    while (iter.next()) {
        iter.fDevice->drawRect(iter, r, looper.paint());
    }


    LOOPER_END


先完全展开上面的代码:
AutoDrawLooper  looper(this, paint, false, bounds);
while (looper.next(type)) {
    SkDrawIter          iter(this);
    while (iter.next()) {
        iter.fDevice->drawRect(iter, r, looper.paint());
    }
}


第一重循环即 AutoDrawLooper,这个next实际上是做一个后处理,在存在 SkImageFilter 的情况下,先渲染到临时Layer上,再将这个Layer做Filter处理后画到当前device上。
第二重循环是SkDrawIter,这个是绘制当前状态所依附的所有Layer。
一般情况下,这两重循环都可以忽略,单纯当它是走下流程就好了。


个人认为Skia在绘制入口SkCanvas的设计并不是很好,图层、矩阵与裁剪存在一起,导致渲染任务难以剥离,后面GPU渲染和延迟渲染的引入都让人感到有些生硬。


2、SkDraw、SkBlitter
这两个类在后续章节还会提到,这里只简单介绍:
SkDraw是CPU绘图的实现入口,主要任务是做渲染准备(形状确定、几何变换、字体解析、构建图像Shader等)。
SkBlitter 不是单独的一个类,指代了一系列根据图像格式、是否包含Shader等区分出来的一系列子类。
这一族类执行大块头的渲染任务,把像素绘制上去。





三、渲染框架设计思想分析
1、指令层与实现层分离
SkCanvas不直接执行渲染,由SkBaseDevice根据设备类型,选择渲染方法。这样虽然是同一套API,但可以用作GPU绘图、pdf绘制、存储显示列表等各种功能。在API集上做优化,避免冗余绘制,也因此成为可能(注:这个google虽然在尝试,但目前看来没有明显效果,实现起来确实也很困难)。
2、图=形+色的设计思想
由SkDraw和SkScan类中控制绘制的形,由SkBlitter和SkShader控制绘制的色,将绘图操作分解为形状与色彩两部分,这一点和OpenGL的顶点变换——光栅——片断着色管线相似,非常有利于扩展,各种2D图元的绘制基本上就完全支持了。
3、性能调优集中化
将耗时的函数抽象都抽象为proc,由一个工厂制造,便于集中对这一系列函数做优化。


下面三章分别讲bitmap、path和text的绘制方法
着重点分别如下:
bitmap:shader及采样原理,混合计算原理,多格式支持方法
path:不规则图形的绘制方式
text:文本解析方法,cache管理

版权声明:本文为博主原创文章,未经博主允许不得转载。

© 著作权归作者所有

共有 人打赏支持
jxt1234
粉丝 5
博文 36
码字总数 41634
作品 0
杭州
私信 提问
万万没想到——flutter这样外接纹理

前言 记得在13年做群视频通话的时候,多路视频渲染成为了端上一个非常大的性能瓶颈。原因是每一路画面的高速上屏(PresentRenderBuffer or SwapBuffer 就是讲渲染缓冲区的渲染结果呈现到屏幕...

闲鱼技术
08/22
0
0
Android Graphic : apk and Skia/OpenGL|ES

Android apk里面的画图分为2D和3D两种:2D是由 Skia 来实现的,也就是我们在框架图上看到的SGL,SGL也会调用部分opengl的内容来实现简单的3D效果;3D部分是由OpenGL|ES实现的,OpenGL|ES是O...

Jerikc
2014/05/27
0
0
Skia构建系统与编译脚本分析

版权声明:本文为foruok原创文章,转载请通过订阅号“程序视界”联系foruok获取授权。 https://blog.csdn.net/foruok/article/details/50699101 分析下Skia的构建系统,具体编译过程参看Win...

foruok
2016/02/19
0
0
谷歌开发者大会2018实录——Flutter篇

摘要 一年一度的google开发者大会即将开始,今年的大会上,flutter会以什么样的形态展现在大家面前,1.0版本何时发布?有哪些应用场景?性能的表现如何?国内的flutter开发者生态又是怎样的?...

阿里云云栖社区
09/27
0
0
Google 图形处理引擎--Skia

skia是个2D向量图形处理函数库,包含字型、座标转换,以及点阵图都有高效能且简洁的表现。不仅用于Google Chrome浏览器,新兴的Android开放手机平台也采用skia作为绘图处理,搭配OpenGL/ES与...

匿名
2009/06/26
23.8K
1

没有更多内容

加载失败,请刷新页面

加载更多

TiQuery:All Diagnosis in SQL | TiDB Hackathon 优秀项目分享

本文作者是来自 TiNiuB 队的黄梦龙同学,他们的项目 TiQuery 在本届 TiDB Hackathon 2018 中获得了三等奖。 TiQuery 可以搜集诊断集群问题所需要的信息,包括集群拓扑,Region 分布,配置,各...

TiDB
18分钟前
2
0
git 分支创建合并流程图

gentlelions
26分钟前
3
0
Kali Linux常用服务配置教程DHCP服务原理

Kali Linux常用服务配置教程DHCP服务原理 动态主机配置协议(Dynamic Host Configuration Protocol,简称DHCP)是一个局域网的网络协议,基于UDP协议工作。它主要有两个用途:第一,给内部网...

大学霸
27分钟前
2
0
控制台打印图片

function dev(){ if (window.console){ console.log("%c\n ", "font-size:100px;background:url('http://gmcyzs.com/resources/images/logo.png') no-repeat"); console.log('%c 深务平台,\......

羊皮卷
34分钟前
0
0
MyBaties的二级缓存

二级缓存介绍 在上文中提到的一级缓存中,其最大的共享范围就是一个SqlSession内部,那么如何让多个SqlSession之间也可以共享缓存呢,答案是二级缓存。 当开启二级缓存后,会使用CachingExec...

嘴角轻扬30
35分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部