一,渲染层级
从渲染流程
上分,Skia
可分为如下三个层级:
1
,指令层:SkPicture,SkDeferredCanvas->SkCanvas
这一层决定要绘图
的操作,绘图操作的预变换矩阵
,当前裁剪区域
,在哪些层
上绘图,层
的生成与合并.
2
,解析层:SkBitmapDevice->SkDraw->SkScan,SkDraw1Glyph::Proc
这一层决定绘画方式
,完成坐标变换
,解析
出需要绘画
的形体(点/线/规整矩形)
并做好抗锯齿
处理,解析好相关资源
并设置Shader
.
3
,渲染层:SkBlitter->SkBlitRow::Proc,SkShader::shadeSpan
等
(如果需要)这一层采样
,产生实际绘画效果
,完成适配颜色格式
,(如果需要)透明度混合
和抖动处理
.
二,主要类介绍
1,SkCanvas
这是复杂度超出想像的一个类.
(1)API
设计
a
,创建:
在安卓
中,主要,由SkBitmap
创建SkCanvas
:
explicit SkCanvas(const SkBitmap& bitmap);
该方法由bitmap
创建一个SkBitmapDevice
,再设置该SkBitmapDevice
为SkCanvas
的渲染目标.
5.0
之后,提供了创建SkCanvas
的快捷方法:
static SkCanvas* NewRasterDirect(const SkImageInfo&, void*, size_t);
这样,GraphicBuffer
就不需要创建与它关联的SkBitmap
.
5.0
之后引入的离屏渲染
:
static SkCanvas* NewRaster(const SkImageInfo&);
创建通过readPixels
读取绘画内容的SkCanvas
,仍是CPU
绘图.
b
,状态:
1,矩阵状态:
矩阵
决定当前绘画
的几何变换
:
rotate,skew,scale,translate,concat
2,裁剪状态:
裁剪
决定当前绘画的生效区间
:
clipRect,clipRRect,clipPath,clipRegion
3,保存与恢复:
save,saveLayer,saveLayerAlpha,restore
c
,渲染:
大部分渲染的API
都可由这三个组合而成:
drawRect
(矩形/图像绘画),drawPath
(不规则图形图像绘画)和drawText
(文本绘画)
d
,读取与写入像素:
readPixels,writePixels
考虑不同绘图
设备的异质性
,主要由设备
实现.
(2)MCRec
状态栈
fMCStack
是存储的全部状态集
,fMCRec
则是当前的状态.
在save/saveLayer/saveLayerAlpha
时,会新建一个在restore
时,析构栈顶的MCRec
.
每个状态包括如下信息:
class SkCanvas::MCRec {
public:int fFlags;//保存的状态标识(是否保存矩阵/裁剪/图层)矩阵指针.SkMatrix* fMatrix;//若该状态有独立矩阵,则指向内存`(fMatrixStorage)`,否则用上一个`MCRec`的`fMatrix`.SkRasterClip* fRasterClip;//裁剪区域,若该状态有独立裁剪区域,则指向内存`(fRasterClip)`,否则继承上一个的.SkDrawFilter* fFilter;DeviceCM* fLayer;//该状态所拥有的`层`(需要在此`MCRec`析构时回收)DeviceCM* fTopLayer;//该状态下,要求要绘画的`层`链表.(这些`层`不一定属于此状态)......
};
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
时,先渲染
到临时层
上,再处理该层
,过滤
后画到当前设备
上.
第二重循环是,绘画当前状态
所依附的所有层
的SkDrawIter
.
一般,都可忽略这两重循环
.
个人认为Skia
在绘画入口SkCanvas
的设计并不是很好,图层,矩阵与裁剪
混一起,导致难以去掉渲染任务
,后面引入GPU
渲染和延迟渲染
都让人感到有些生硬.
2,SkDraw,SkBlitter
这里简单介绍:
SkDraw
是CPU
绘图的实现入口
,主要任务是准备渲染
(形状确定,几何变换,字体解析,构建图像Shader
等).
SkBlitter
不是单独的一个类,而是指代了一系列根据图像格式
,是否包含Shader
等区分
出来的一系列子类
.
这一族类
执行真正的渲染任务
,来绘画像素
.