简介:
Snapshot可以称为快照,hwui就是通过Snapshot的方式来组织整个渲染状态的,Snapshot保存了当前渲染所需的视口,变换矩阵,裁剪区域,fbo信息等。同时还保存了当前Snapshot的上一个Snapshot,也就是通过栈的方式来组织Snapshot之间的关系的。Snapshot之间的关系:
如图所示,在OpenGLRenderer类创建的时候,将会创建一个空的Snapshot,也就是FirstSnapshot,也可以称之为根节点,接着每次创建新的节点,都将会保存上一次的节点指针,新节点都用指针mSnapshot,来指向当年的节点,其实这就是用栈的形式来存储hwui的绘制状态,通过设置好Snapshot后,后续的绘图操作都会在mSnapshot(当前快照)上进行操作,当当前的绘制操作完成后,可以返回到上一次的Snapshot中,下一次的绘制操作不会影响上一次的绘制操作,但是上一次的绘制操作,可以通过设置来确定是否可以影响下一次Snapshot的渲染状态。
Snapshot的创建与切换:
当OpenGLRenderer构造函数调用的时候将会创建FirstSnapshot,也就是根节点指针,接着当用户调用save时,将创建一个Snapshot,参数为flags,也就是用户在编写是用canvas调用save时输入的参数,默认为全部保存:
int ALL_SAVE_FLAG restore everything when restore() is called
int CLIP_SAVE_FLAG restore the current clip when restore() is called
int CLIP_TO_LAYER_SAVE_FLAG clip against the layer's bounds
int FULL_COLOR_LAYER_SAVE_FLAG the layer needs to 8-bits per color component
int HAS_ALPHA_LAYER_SAVE_FLAG the layer needs to per-pixel alpha
int MATRIX_SAVE_FLAG restore the current matrix when restore() is called
当Snapshot创建时,将主要用到CLIP_SAVE_FLAG与MATRIX_SAVE_FLAG,也就是用于决定当前的矩阵信息当调用restore的时候是否要作用到上一个节点中:
Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags):
flags(0), previous(s), layer(s->layer), fbo(s->fbo),
invisible(s->invisible), empty(false),
viewport(s->viewport), height(s->height), alpha(s->alpha) {
if (saveFlags & SkCanvas::kMatrix_SaveFlag) {
mTransformRoot.load(*s->transform);
transform = &mTransformRoot;
} else {
transform = s->transform;
}
if (saveFlags & SkCanvas::kClip_SaveFlag) {
mClipRectRoot.set(*s->clipRect);
clipRect = &mClipRectRoot;
if (!s->clipRegion->isEmpty()) {
mClipRegionRoot.op(*s->clipRegion, SkRegion::kUnion_Op);
}
clipRegion = &mClipRegionRoot;
} else {
clipRect = s->clipRect;
clipRegion = s->clipRegion;
}
if (s->flags & Snapshot::kFlagFboTarget) {
flags |= Snapshot::kFlagFboTarget;
region = s->region;
} else {
region = NULL;
}
}
如上代码所示 ,首先将上一次的Snapshot保存到previous中,接着去判断输入的saveFlags,如果是MATRIX_SAVE_FLAG,则将调用load将上一节点的矩阵信息拷贝一份,否则将上一次的矩阵信息的指针保存到当前的变换矩阵transform中,这样后续对transform的操作都将会保存到上一次的Snapshot中,当调用restore的时候,将会将当前的变换矩阵作用到上一次的矩阵中。CLIP_SAVE_FLAG同理。
同时,Snapshot也可以用于保存fbo的layer信息,如当用户调用saveLayer的时候,将会创建一个Layer,Layer也就是一块绘制区域,这块绘制区域单独渲染,即使用fbo的形式。
接着介绍两个Snapshot两个比较重要的变量:
Rect* clipRect;
SkRegion* clipRegion;
这两个变量很容易混淆,clipRect就是裁剪矩形,它只有四个值左上右下,它的作用就是保存当前的Snapshot的最大裁剪矩形,它一定是矩形的,而第二个变量clipRegion即裁剪区域,这是个区域,它可以由各种复杂形状组成,clipRect则是由clipRegion计算出最大的bound的矩形,来作为裁剪矩形,用于设置opengl的裁剪的,而clipRegion则是不规则的裁剪区域,用于限定一个绘制指令只有在该区域内才能生效的,这个将在最后绘制时,首先会将它用来生成许多一个像素高度的小矩形来绘制,用来作为模板测试使用,也就是只有通过模板测试的才能绘制,否则就丢弃。