hwui绘制状态组织方式——Snapshot

简介:

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& 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则是不规则的裁剪区域,用于限定一个绘制指令只有在该区域内才能生效的,这个将在最后绘制时,首先会将它用来生成许多一个像素高度的小矩形来绘制,用来作为模板测试使用,也就是只有通过模板测试的才能绘制,否则就丢弃。


你可能感兴趣的:(HWUI,HWUI,Snapshot,绘制状态,android)