学习做网站的网站,公司注册地址变更网上流程怎么办,生态养殖网站模板,wordpress全静态一、概述
在上一篇文章中已经讲了setView整个流程中#xff0c;最开始的addToDisplay和WMS跨进程通信的整个过程做了什么。继文章Android基础知识之Window(二)#xff0c;这算是另外一个分支了#xff0c;接着讲分析在performTraversals的三个操作中#xff0c;最后触发pe…一、概述
在上一篇文章中已经讲了setView整个流程中最开始的addToDisplay和WMS跨进程通信的整个过程做了什么。继文章Android基础知识之Window(二)这算是另外一个分支了接着讲分析在performTraversals的三个操作中最后触发performDraw执行绘制的绘制原理。
二、SurfaceFlinger基础
SurfaceFlinger是Android操作系统中一个关键组件负责管理和合成显示内容。你说它是显示引擎也可以说他是Android的显示服务器也可以。
2.1 创建
它属于一个独立的进程在系统启动过程中会通过init进程解析init.rc然后再去加载SurfaceFlinger。最后加载的路径在*/frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp*执行它的main函数。
//main_surfaceflinger.cpp
int main(int, char**) {signal(SIGPIPE, SIG_IGN);...// start the thread poolspProcessState ps(ProcessState::self());ps-startThreadPool();...// instantiate surfaceflinger// 实例化SurfaceFlingerspSurfaceFlinger flinger surfaceflinger::createSurfaceFlinger();...2.2 图形系统概要
这里简单的介绍一下图形系统应用程序可以借助图形系统在屏幕上显示画面与用户完成交互。把图形系统进行划分可以分为UI框架、渲染系统Skia/OpenGL、窗口系统X11/Wayland/SurfaceFlinger、显示系统DRM/显示驱动等可以看到讲的SurfaceFlinger属于系统层级中的窗口系统。
显示系统对屏幕的抽象和封装渲染系统抽象和封装GPU提供的渲染能力窗口系统把一块屏幕拆分为几个window使得多个应用同时使用屏幕UI框架向应用程序提供与用户交互的能力 纵向分层从下层至上层分为 GPU - GPU驱动 - OpenGL - 2D图形库Skia等- UI框架Android原生View /Flutter等 在来说一下渲染和绘制这两个概念很多地方经常会互用但也没有问题有时候我们说渲染某个画面或者绘制某个画面也是同一个意思。但是如果需要认真区分它们就是两个不同的概念了。
绘制View - 2D几何图形矩阵/圆/三角形和文字渲染点/直线/三角面片/ - 光栅化/着色像素矢量图转变位图
三、绘制
基本的概念补充了一下就讲这次的主要内容了performTraversals执行了测量、布局、和绘制三个操作前面两个操作都是为最后一个绘制做的准备工作。在应用上层中常常提到的绘制我们知道是执行View#onDraw方法可是怎么执行进来的在之前文章中只是讲了一个大概这次就详细分析一下这个流程perfromDraw中主要的函数draw。
//ViewRootImpl.java
private boolean draw(boolean fullRedrawNeeded, boolean forceDraw) {...//DEBUG下可以捕获当前fps值if (DEBUG_FPS) {trackFPS();}...//脏视图的集合是否为空有没有变化的视图区域if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {//判断是否开启了硬件加速是否硬件支持if (isHardwareEnabled()) {...//硬件绘制ThreadRenderer进行绘制mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);} else {...//软件绘制if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset,scalingRequired, dirty, surfaceInsets)) {return false;}}}
}3.1 drawSoftware
先看一下软件绘制drawSoftware做了什么一般情况没有开启硬件加速在performDraw执行进来过后就执行这部分逻辑。
//ViewRootImpl.java
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,boolean scalingRequired, Rect dirty, Rect surfaceInsets) {// Draw with software renderer.final Canvas canvas;try {//拿到Surface的画布canvas mSurface.lockCanvas(dirty);canvas.setDensity(mDensity);} catch (Surface.OutOfResourcesException e) {handleOutOfResourcesException(e);return false;} catch (IllegalArgumentException e) {Log.e(mTag, Could not lock surface, e);mLayoutRequested true; // ask wm for a new surface next time.return false;}try {if (!canvas.isOpaque() || yoff ! 0 || xoff ! 0) {canvas.drawColor(0, PorterDuff.Mode.CLEAR);}//清空脏视图缓存dirty.setEmpty();mIsAnimating false;mView.mPrivateFlags | View.PFLAG_DRAWN;canvas.translate(-xoff, -yoff);if (mTranslator ! null) {mTranslator.translateCanvas(canvas);}canvas.setScreenDensity(scalingRequired ? mNoncompatDensity : 0);//回调到View的onDraw方法mView.draw(canvas);drawAccessibilityFocusedDrawableIfNeeded(canvas);} finally {try {//将后缓冲区提交到前缓冲区显示surface.unlockCanvasAndPost(canvas);} catch (IllegalArgumentException e) {Log.e(mTag, Could not unlock surface, e);mLayoutRequested true; // ask wm for a new surface next time.//noinspection ReturnInsideFinallyBlockreturn false;}}return true;
} mSurface是ViewRootImpl创建的一个Surface对象也就说明一个windnow对应一个Surface和SurfaceControl对象这个在之前文章有讲过。Surface涉及的双缓冲机制分前缓冲区和后缓冲区前缓冲区用于显示绘制在后缓冲区绘制完成通过unlockCanvasAndPost和前缓冲区互换完成显示防止闪烁的问题。这里我们看到了mView#draw方法回调View当中的onDraw通过Surface拿到的canvas执行绘制代码。 补充ViewRootImpl 和 SurfaceView 可以看作是一个层级的事物他们都持有一个 surfaceViewRootImpl 自己把 ViewTree 渲染到 surface 上SurfaceView 的 surface 供应用自行使用应用可以把游戏/视频/相机/3D图形库生成数据放到 surface 上 3.2 ThreadedRenderer#draw
然后继续看一下mAttachInfo.mThreadedRenderer.draw这个方法mThreadedRenderer是我们常说的渲染线程mAttachInfo属于View类中的一个内部类。在performTraversals中会判断并执行enableHardwareAcceleration然后创建renderer对象。
//ViewRootImpl.javaUnsupportedAppUsageprivate void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {...if (ThreadedRenderer.sRendererEnabled || forceHwAccelerated) {if (mAttachInfo.mThreadedRenderer ! null) {mAttachInfo.mThreadedRenderer.destroy();}final Rect insets attrs.surfaceInsets;final boolean hasSurfaceInsets insets.left ! 0 || insets.right ! 0|| insets.top ! 0 || insets.bottom ! 0;final boolean translucent attrs.format ! PixelFormat.OPAQUE || hasSurfaceInsets;final ThreadedRenderer renderer ThreadedRenderer.create(mContext, translucent,attrs.getTitle().toString());mAttachInfo.mThreadedRenderer renderer;renderer.setSurfaceControl(mSurfaceControl, mBlastBufferQueue);updateColorModeIfNeeded(attrs.getColorMode());updateRenderHdrSdrRatio();updateForceDarkMode();mAttachInfo.mHardwareAccelerated true;mAttachInfo.mHardwareAccelerationRequested true;if (mHardwareRendererObserver ! null) {renderer.addObserver(mHardwareRendererObserver);}}}
}代码我们可以看到通过ThreadedRenderer#create的静态方法创建renderer对象并赋值给了mAttachInfo.mThreadedRenderer属性。继续看一下renderer#draw方法。
//ThreadedRenderer.java/*** Draws the specified view.** param view The view to draw.* param attachInfo AttachInfo tied to the specified view.*/void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {attachInfo.mViewRootImpl.mViewFrameInfo.markDrawStart();updateRootDisplayList(view, callbacks);// register animating rendernodes which started animating prior to renderer// creation, which is typical for animators started prior to first drawif (attachInfo.mPendingAnimatingRenderNodes ! null) {final int count attachInfo.mPendingAnimatingRenderNodes.size();for (int i 0; i count; i) {registerAnimatingRenderNode(attachInfo.mPendingAnimatingRenderNodes.get(i));}attachInfo.mPendingAnimatingRenderNodes.clear();// We dont need this anymore as subsequent calls to// ViewRootImpl#attachRenderNodeAnimator will go directly to us.attachInfo.mPendingAnimatingRenderNodes null;}final FrameInfo frameInfo attachInfo.mViewRootImpl.getUpdatedFrameInfo();int syncResult syncAndDrawFrame(frameInfo);if ((syncResult SYNC_LOST_SURFACE_REWARD_IF_FOUND) ! 0) {Log.w(OpenGLRenderer, Surface lost, forcing relayout);// We lost our surface. For a relayout next frame which should give us a new// surface from WindowManager, which hopefully will work.attachInfo.mViewRootImpl.mForceNextWindowRelayout true;attachInfo.mViewRootImpl.requestLayout();}if ((syncResult SYNC_REDRAW_REQUESTED) ! 0) {attachInfo.mViewRootImpl.invalidate();}}方法注解说明是一个绘制指定View的方法AttachInfo绑定到指定View上。syncAndDrawFrame是父类HardwareRenderer的一个方法调用的是native方法。再看一下updateRootDisplayList。
//ThreadedRenderer.javaprivate void updateRootDisplayList(View view, DrawCallbacks callbacks) {Trace.traceBegin(Trace.TRACE_TAG_VIEW, Record View#draw());//更新view的一些标志位updateViewTreeDisplayList(view);if (mNextRtFrameCallbacks ! null) {final ArrayListFrameDrawingCallback frameCallbacks mNextRtFrameCallbacks;mNextRtFrameCallbacks null;//设置每帧的绘制回调setFrameCallback(new FrameDrawingCallback() {Overridepublic void onFrameDraw(long frame) {}Overridepublic FrameCommitCallback onFrameDraw(int syncResult, long frame) {ArrayListFrameCommitCallback frameCommitCallbacks new ArrayList();for (int i 0; i frameCallbacks.size(); i) {FrameCommitCallback frameCommitCallback frameCallbacks.get(i).onFrameDraw(syncResult, frame);if (frameCommitCallback ! null) {frameCommitCallbacks.add(frameCommitCallback);}}if (frameCommitCallbacks.isEmpty()) {return null;}return didProduceBuffer - {for (int i 0; i frameCommitCallbacks.size(); i) {frameCommitCallbacks.get(i).onFrameCommit(didProduceBuffer);}};}});}if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {//拿到RecordingCanvas对象通过mRootNode获取RecordingCanvas canvas mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);try {final int saveCount canvas.save();canvas.translate(mInsetLeft, mInsetTop);callbacks.onPreDraw(canvas);canvas.enableZ();//执行canvas的drawRenderNode来执行mRootNode绘制canvas.drawRenderNode(view.updateDisplayListIfDirty());canvas.disableZ();callbacks.onPostDraw(canvas);canvas.restoreToCount(saveCount);mRootNodeNeedsUpdate false;} finally {mRootNode.endRecording();}}Trace.traceEnd(Trace.TRACE_TAG_VIEW);RecordingCanvas是Canvas的一个子类而RecordingCanvas#drawRenderNode方法将绘制任务传递给本地层调用了nDrawRenderNode是一个native方法。/frameworks/base/libs/hwui/jni/android_graphics_DisplayListCanvas.cpp
//SkiaRecordingCavas.app
void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {// Record the child node. Drawable dtor will be invoked when mChildNodes deque is cleared.mDisplayList-mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);auto renderNodeDrawable mDisplayList-mChildNodes.back();if (Properties::getRenderPipelineType() RenderPipelineType::SkiaVulkan) {// Put Vulkan WebViews with non-rectangular clips in a HW layerrenderNode-mutateStagingProperties().setClipMayBeComplex(mRecorder.isClipMayBeComplex());}drawDrawable(renderNodeDrawable);// use staging property, since recording on UI threadif (renderNode-stagingProperties().isProjectionReceiver()) {mDisplayList-mProjectionReceiver renderNodeDrawable;}
}SkiaRecordingCanvas是一个用于记录绘制命令的类。renderNode是一个记录了绘制命令的对象。DisplayList用来存储ViewTree中需要绘制的View所生成的renderNode节点。 1、mDisplayList把RenderNode节点添加到它的mChildNodes列表的尾部 2、然后取出列表尾部这个元素赋值给renderNodeDrawable 3、执行drawDrawable函数传入renderNodeDrawable地址 4、Drawable#draw会将绘制命令传递给SkCanvas 5、Skia图形库再将绘制命令转换为GPU指令并通过OpenGL等图形API发送到GPU进行渲染 SkCanvas是Skia图形库的核心类用于执行具体的绘制操作。 软件绘制通过Surface.unlockCanvasAndPost把提交绘制结果到SurfaceFlinger。硬件绘制通过使用GPU进行绘制并通过OpenGL等图形API与SurfaceFlinger通信。它们最后都实现了SurfaceFlinger的通信过程并提交了结果SurfaceFlinger负责合成各个窗口的内容并将最终的显示结果提交到屏幕上。
这里给出了Activity一帧的绘制流程
总结
1、performDraw分两个流程软件绘制和硬件绘制 2、软件绘制直接在ViewRootImpl创建的Surface进行绘制并提交给SurfaceFlinger 3、判断启动硬件加速会创建Render对象 4、硬件绘制通过RecordingCanvas提交绘制任务给本地层 5、RenderNode会记录绘制命令并将绘制命令传递给SkCanvas上 6、Skia图形库将命令转换成GPU指令交由GPU进行渲染
之后最后一篇文章主要围绕整个图形系统详细讲讲SurfaceFlinger的概念。