Android应用程序UI硬件加速渲染的Display List构建过程分析Word文档下载推荐.docx
- 文档编号:5744706
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:70
- 大小:209.12KB
Android应用程序UI硬件加速渲染的Display List构建过程分析Word文档下载推荐.docx
《Android应用程序UI硬件加速渲染的Display List构建过程分析Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《Android应用程序UI硬件加速渲染的Display List构建过程分析Word文档下载推荐.docx(70页珍藏版)》请在冰点文库上搜索。
此外,一个视图如果设置有Background,那么这个Background也会抽象为一个BackgroundRenderNode。
RootRenderNode、BackgroundRenderNode和其它真实的子视图,除了TextureView和软件渲染的子视图之外,都具有DisplayList,并且是通过一个称为DisplayListRenderer的对象进行构建的。
TextureView不具有DisplayList,它们是通过一个称为LayerRenderer的对象以OpenGL纹理的形式来绘制的,不过这个纹理也不是直接就进行渲染的,而是先记录在父视图的DisplayList中以后再进行渲染的。
同样,软件渲染的子视图也不具有DisplayList,它们先绘制在一个Bitmap上,然后这个Bitmap再记录在父视图的DisplayList中以后再进行渲染的。
最后,RootRenderNode的DisplayList被一个称为OpenGLRenderer的对象进行渲染,就得到Android应用程序窗口的UI了。
接下来我们就结合源代码来分析Android应用程序窗口视图的DisplayList的构建过程。
在前面一文提到,Android应用程序窗口UI的绘制过程是从ViewRootImpl类的成员函数performDraw开始的,它的实现如下所示:
[java]viewplaincopy
publicfinalclassViewRootImplimplementsViewParent,
View.AttachInfo.Callbacks,HardwareRenderer.HardwareDrawCallbacks{
......
privatevoidperformDraw(){
try{
draw(fullRedrawNeeded);
}finally{
}
}
这个函数定义在文件frameworks/base/core/java/android/view/ViewRootImpl.java中。
ViewRootImpl类的成员函数performDraw主要是调用了另外一个成员函数draw执行UI绘制工作,后者的实现如下所示:
privatevoiddraw(booleanfullRedrawNeeded){
finalRectdirty=mDirty;
if(!
dirty.isEmpty()||mIsAnimating){
if(mAttachInfo.mHardwareRenderer!
=null&
&
mAttachInfo.mHardwareRenderer.isEnabled()){
mAttachInfo.mHardwareRenderer.draw(mView,mAttachInfo,this);
}else{
drawSoftware(surface,mAttachInfo,xOffset,yOffset,scalingRequired,dirty)){
return;
经过一些滚动相关的处理之后,在两种情况下,需要真正地重绘窗口的下一帧。
第一种情况是当前需要更新的区域,即ViewRootImpl类的成员变量mDirty描述的脏区域不为空。
第二种情况下窗口当前有动画需要执行,即ViewRootImpl类的成员变量mIsAnimating的值等于true。
在上述两种情况下,如果ViewRootImpl类的成员变量mAttachInfo指向的一个AttachInfo对象的成员变量mHardwareRenderer的值不为null,并且调用它指向的一个HardwareRenderer对象的成员函数isEnabled的返回值为true,那么就调用这个HardwareRenderer对象的另外一个成员函数draw执行渲染工作。
从前面一文可以知道,当使用硬件加速渲染时,ViewRootImpl类的成员变量mAttachInfo指向的一个AttachInfo对象的成员变量mHardwareRenderer的值不为null,并且它指向的是一个ThreadedRenderer对象。
如果该ThreadedRenderer对象也设置了支持硬件加速渲染,那么调用它的成员函数isEnabled的返回值就为true。
这意味着当使用硬件加速渲染时,ViewRootImpl类的成员函数draw调用的是ThreadedRenderer类的成员函数draw。
另一方面,当使用软件渲染时,ViewRootImpl类的成员函数draw调用的是另外一个成员函数drawSoftware。
软件渲染的执行过程可以参考前面一文。
这里我们只关注硬件渲染的执行过程,因此接下来我们继续分析ThreadedRenderer类的成员函数draw的实现,如下所示:
publicclassThreadedRendererextendsHardwareRenderer{
@Override
voiddraw(Viewview,AttachInfoattachInfo,HardwareDrawCallbackscallbacks){
updateRootDisplayList(view,callbacks);
if(attachInfo.mPendingAnimatingRenderNodes!
=null){
finalintcount=attachInfo.mPendingAnimatingRenderNodes.size();
for(inti=0;
i<
count;
i++){
registerAnimatingRenderNode(
attachInfo.mPendingAnimatingRenderNodes.get(i));
attachInfo.mPendingAnimatingRenderNodes.clear();
//Wedon'
tneedthisanymoreassubsequentcallsto
//ViewRootImpl#attachRenderNodeAnimatorwillgodirectlytous.
attachInfo.mPendingAnimatingRenderNodes=null;
intsyncResult=nSyncAndDrawFrame(mNativeProxy,frameTimeNanos,
recordDuration,view.getResources().getDisplayMetrics().density);
if((syncResult&
SYNC_INVALIDATE_REQUIRED)!
=0){
attachInfo.mViewRootImpl.invalidate();
这个函数定义在文件frameworks/base/core/Java/android/view/ThreadedRenderer.java中。
ThreadedRenderer类的成员函数draw主要是完成以下四件事情:
1.调用成员函数updateRootDisplayList构建参数view描述的视图的DisplayList,该视图即为图1所示的DecorView。
2.调用成员函数registerAnimatingRenderNode将保存在参数attachInfo指向的一个AttachInfo对象的成员变量mPendingAnimatingRenderNodes描述的一个列表中的RenderNode注册到Native层中去。
这些RenderNode描述的是当前窗口设置的动画。
3.调用成员函数nSyncAndDrawFrame通知RenderThread绘制下一帧。
4.如果成员函数nSyncAndDrawFrame的返回值syncResult的SYNC_INVALIDATE_REQUIRED位不等于0,就表明RenderThread可能需要与MainThread进行信息同步,这时候就时候向MainThread发送一个INVALIDATE消息,以便MainThread可以进行信息同步。
这种情况一般发生在当前绘制的一帧包含有同步动画时。
例如,同步动画显示到一半,需要中止,这个中止的操作就是由MainThread发出的,然后由RenderThread检测到这个中止操作。
这里我们只关注第一件事情,其余三件事情在接下来的两篇文章中再详细分析。
ThreadedRenderer类的成员函数updateRootDisplayList的实现如下所示:
privatevoidupdateRootDisplayList(Viewview,HardwareDrawCallbackscallbacks){
updateViewTreeDisplayList(view);
if(mRootNodeNeedsUpdate||!
mRootNode.isValid()){
HardwareCanvascanvas=mRootNode.start(mSurfaceWidth,mSurfaceHeight);
finalintsaveCount=canvas.save();
.......
canvas.insertReorderBarrier();
canvas.drawRenderNode(view.getDisplayList());
canvas.insertInorderBarrier();
canvas.restoreToCount(saveCount);
mRootNodeNeedsUpdate=false;
mRootNode.end(canvas);
这个函数定义在文件frameworks/base/core/java/android/view/ThreadedRenderer.java中。
ThreadedRenderer类的成员函数updateRootDisplayList通过调用另一个成员函数updateViewTreeDisplayList来构建参数view描述的视图的DisplayList,即图1中的DecorView的DisplayList。
构建好的这个DisplayList可以通过调用参数view描述的视图的成员函数getDisplayList获得的一个RenderNode来描述。
ThreadedRenderer类的成员变量mRootNodeNeedsUpdate是一个布尔变量,当它的值等于true的时候,就表示要更新另外一个成员变量mRootNode描述的一个RenderNode的DisplayList。
另外,如果ThreadedRenderer类的成员变量mRootNode描述的RenderNode还未构建过DisplayList,那么这时候调用它的成员函数isValid的返回值为true,这种情况也表示要更新它的DisplayList。
从前面一文可以知道,ThreadedRenderer类的成员变量mRootNode描述的RenderNode即为即为当前窗口的RootNode,更新它的DisplayList实际上就是要将参数view描述的视图的DisplayList记录到它里面去,具体方法如下所示:
1.调用ThreadedRenderer类的成员变量mRootNode描述的RenderNode的成员函数start获得一个HardwareCanvas。
2.调用上面获得的HardwareCanvas的成员函数drawRenderNode将参数view描述的视图的DisplayList绘制在它里面。
在绘制参数view描述的视图的DisplayList的前后,会调用HardwareCanvas的成员函数insertReorderBarrier和insertInorderBarrier分别设置一个ReorderBarrier和一个InorderBarrier。
后面我们在分析DisplayList绘制在HardwareCanvas的过程时就会看到,插入这些Barrier是为了将一个View的所有的DrawOp及其子View对应的DrawOp记录在一个Chunk中。
其中,ReorderBarrier表明在真正渲染这些Chunck记录的DrawOp时,需要考虑按照Z轴坐标值重新排列子View的渲染顺序。
3.调用ThreadedRenderer类的成员变量mRootNode描述的RenderNode的成员函数end取出上述已经绘制好的HardwareCanvas的数据,并且作为上述RenderNode的新的DisplayList。
接下来,我们首先分析ThreadedRenderer类的成员变量mRootNode描述的RenderNode的DisplayList的更新过程,即RootNode类的成员函数start、HardwareCanvas类的成员函数drawRenderNode和RootNode类的成员函数end的实现,然后再回过头来分析参数view描述的视图的DisplayList的构建过程,即ThreadedRenderer类的成员函数updateViewTreeDisplayList的实现。
RootNode类的成员函数start的实现如下所示:
publicclassRenderNode{
publicHardwareCanvasstart(intwidth,intheight){
HardwareCanvascanvas=GLES20RecordingCanvas.obtain(this);
canvas.setViewport(width,height);
returncanvas;
这个函数定义在文件frameworks/base/core/java/android/view/RenderNode.java中。
RootNode类的成员函数start的核心是调用GLES20RecordingCanvas类的静态成员函数obtain一个类型为GLES20RecordingCanvas的HardwareCanvas,然后在设置了该HardwareCanvas的ViewPort之后,返回给调用者。
GLES20RecordingCanvas类的静态成员函数obtain的实现如下所示:
classGLES20RecordingCanvasextendsGLES20Canvas{
privatestaticfinalintPOOL_LIMIT=25;
privatestaticfinalSynchronizedPool<
GLES20RecordingCanvas>
sPool=
newSynchronizedPool<
(POOL_LIMIT);
RenderNodemNode;
privateGLES20RecordingCanvas(){
super();
staticGLES20RecordingCanvasobtain(@NonNullRenderNodenode){
GLES20RecordingCanvascanvas=sPool.acquire();
if(canvas==null){
canvas=newGLES20RecordingCanvas();
canvas.mNode=node;
这个函数定义在文件frameworks/base/core/java/android/view/GLES20RecordingCanvas.java中。
GLES20RecordingCanvas类的静态成员函数obtain首先是从一个GLES20RecordingCanvas对象池中请求一个GLES20RecordingCanvas对象。
如果获取失败,再直接创建一个GLES20RecordingCanvas对象。
在将获取到的GLES20RecordingCanvas对象返回给调用者之前,还会将参数node描述的RenderNode保存在其成员变量mNode中。
接下来我们继续关注GLES20RecordingCanvas对象的创建过程,即GLES20RecordingCanvas类的构造函数的实现。
GLES20RecordingCanvas类的构造函数只是简单调用了父类GLES20Canvas的构造函数,它的实现如下所示:
[java]viewplaincopy在CODE上查看代码片派生到我的代码片
classGLES20CanvasextendsHardwareCanvas{
protectedlongmRenderer;
protectedGLES20Canvas(){
mRenderer=nCreateDisplayListRenderer();
这个函数定义在文件frameworks/base/core/java/android/view/GLES20Canvas.java中。
GLES20Canvas类的构造函数最主要做的事情就是调用另外一个成员函数nCreateDisplayListRenderer在Native层创建了一个DisplayListRenderer,并且将它的地址保存在成员变量mRenderer中。
GLES20Canvas类的成员函数nCreateDisplayListRenderer是一个JNI函数,由Native层的函数android_view_GLES20Canvas_createDisplayListRenderer实现,如下所示:
[cpp]viewplaincopy在CODE上查看代码片派生到我的代码片
staticjlongandroid_view_GLES20Canvas_createDisplayListRenderer(JNIEnv*env,jobjectclazz){
returnreinterpret_cast<
jlong>
(newDisplayListR
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android应用程序UI硬件加速渲染的Display List构建过程分析 Android 应用程序 UI 硬件加速 渲染 Display List 构建 过程 分析
链接地址:https://www.bingdoc.com/p-5744706.html