【Android】WMS(六)Surface的创建和操作

Surface的创建流程

在Android系统中每个Activity都有一个独立的画布(在应用侧称为Surface,在SurfaceFlinger侧称为Layer), 无论这个Activity安排了多么复杂的view结构,它们最终都是被画在了所属Activity的这块画布上。

1.Surface在应用端的新建

在 ViewRootImpl 创建时同时会 new 一个 Surface 对象

private final Surface mSurface = new Surface();

在这里插入图片描述
Surface其实是广义上的画布,真正意义上的画图是Canvas,也就是在View的onDraw方法里面的Canvas。

public class Surface implements Parcelable {
......
private final Canvas mCanvas = new CompatibleCanvas();
......
}

ViewRootImpl直接新建的Surface并没有直接大小

2 SurfaceControl

SurfaceControl是创建Surface的辅助管理类,它在ViewRootImpl创建。

 private final SurfaceControl mSurfaceControl = new SurfaceControl();

在setView的时候会调用relayoutWindow函数,由mWindowSession将内容传递给WMS端

  private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
      ......
            int relayoutResult = mWindowSession.relayout(mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility,
                insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, frameNumber,
                mTmpFrame, mTmpRect, mTmpRect, mTmpRect, mPendingBackDropFrame,
                mPendingDisplayCutout, mPendingMergedConfiguration, mSurfaceControl, mTempInsets,
                mTempControls, mSurfaceSize, mBlastSurfaceControl);
      ......
  }

随着代码的执行让我们把视角切换到system_server进程(WMS的relayoutWindow函数),这里会调用createSurfaceControl去创建一个SurfaceControl:

 public int relayoutWindow(Session session, IWindow client, int seq, LayoutParams attrs,
            int requestedWidth, int requestedHeight, int viewVisibility, int flags,
            long frameNumber, Rect outFrame, Rect outContentInsets,
            Rect outVisibleInsets, Rect outStableInsets, Rect outBackdropFrame,
            DisplayCutout.ParcelableWrapper outCutout, MergedConfiguration mergedConfiguration,
            SurfaceControl outSurfaceControl, InsetsState outInsetsState,
            InsetsSourceControl[] outActiveControls, Point outSurfaceSize,
            SurfaceControl outBLASTSurfaceControl) {
     	......
		result = createSurfaceControl(outSurfaceControl, outBLASTSurfaceControl, result, win, winAnimator);
     	......
 }

SurfaceControl的创建过程,注意这里创建工作是调用winAnimator来完成的,注意下面那句surfaceController.getSurfaceControl会把创建出来的SurfaceControl通过形参outSurfaceControl传出去:

private int createSurfaceControl(SurfaceControl outSurfaceControl,
            SurfaceControl outBLASTSurfaceControl, int result,
            WindowState win, WindowStateAnimator winAnimator) {
    ......
    WindowSurfaceController surfaceController;
    try {
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createSurfaceControl");
        surfaceController = winAnimator.createSurfaceLocked(win.mAttrs.type, win.mOwnerUid);
    } finally {
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
    }
    if (surfaceController != null) {
        surfaceController.getSurfaceControl(outSurfaceControl);
        ......
    }
    ......
}

我们先看下创建过程,创建了一个WindowSurfaceController,进而再创建SurfaceControll:

WindowSurfaceController createSurfaceLocked(int windowType, int ownerUid) {
    ......
    /*WindowSurfaceController mSurfaceController;*/
    mSurfaceController = new WindowSurfaceController(attrs.getTitle().toString(), width,
                    height, format, flags, this, windowType, ownerUid);
    ......
}
WindowSurfaceController(String name, int w, int h, int format,
            int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
     ......
     final SurfaceControl.Builder b = win.makeSurface()
                .setParent(win.getSurfaceControl())
                .setName(name)
                .setBufferSize(w, h)
                .setFormat(format)
                .setFlags(flags)
                .setMetadata(METADATA_WINDOW_TYPE, windowType)
                .setMetadata(METADATA_OWNER_UID, ownerUid)
                .setCallsite("WindowSurfaceController");
     ......
}

在WMS端SurfaceControl以形参outSurfaceControl传出,然后在ViewRootImpl侧,通过Surface的copyFrom方法,将内容写入到mSurface,此时surface正式新建完毕。

private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {
    ......
    if (mSurfaceControl.isValid()) {
                if (!useBLAST()) {
                    mSurface.copyFrom(mSurfaceControl);
                }
    }
    ......
}
3 图层Layer创建

在这里插入图片描述

在SurfaceControl的构造方法中通过JNI去创建C端对象

private SurfaceControl(SurfaceSession session, String name, int w, int h, int format, int flags,
            SurfaceControl parent, SparseIntArray metadata, WeakReference<View> localOwnerView,
            String callsite){
    ......
    mNativeObject = nativeCreate(session, name, w, h, format, flags,
                    parent != null ? parent.mNativeObject : 0, metaParcel);
    ......
}
static jlong nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
        jstring nameStr, jint w, jint h, jint format, jint flags, jlong parentObject,
        jobject metadataParcel) {
    ScopedUtfChars name(env, nameStr);//Surface名字, 在SurfaceFlinger侧就是Layer的名字
    ......
    sp<SurfaceComposerClient> client;
    ......
    status_t err = client->createSurfaceChecked(
            String8(name.c_str()), w, h, format, &surface, flags, parent, std::move(metadata));
    ......
}

C层的Surface在创建时去调用SurfaceComposerClient的createSurface去创建, 这个SurfaceComposerClient可以看作是SurfaceFlinger在Client端的代表

status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                     PixelFormat format,
                                                     sp<SurfaceControl>* outSurface, uint32_t flags,
                                                     SurfaceControl* parent, LayerMetadata metadata,
                                                     uint32_t* outTransformHint) {
      ......
      err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
                                     &handle, &gbp, &transformHint);
      ......
sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h,
                                                        PixelFormat format, uint32_t flags,
                                                        SurfaceControl* parent,
                                                        LayerMetadata metadata,
                                                        uint32_t* outTransformHint) {
    sp<SurfaceControl> s;
    createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata),
                         outTransformHint);
    return s;
}
status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                     PixelFormat format,
                                                     sp<SurfaceControl>* outSurface, uint32_t flags,
                                                     SurfaceControl* parent, LayerMetadata metadata,
                                                     uint32_t* outTransformHint) {
      .......
      err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
                                     &handle, &gbp, &transformHint);
      .......
}

跨进程呼叫SurfaceFlinger:

status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format,
                           uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata,
                           sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp,
                           uint32_t* outTransformHint) override {
     return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE,
                               name, width, height,
                               format, flags, parent,
                               std::move(metadata),
                               handle, gbp,
                               outTransformHint);
}

然后流程就来到了SurfaceFlinger进程,由于SurfaceFlinger支持很多不同类型的Layer, 这里我们只以BufferQueueLayer为例, 当SurfaceFlinger收到这个远程调用后会new 一个BufferQueueLayer出来。

tatus_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
                                     uint32_t h, PixelFormat format, uint32_t flags,
                                     LayerMetadata metadata, sp<IBinder>* handle,
                                     sp<IGraphicBufferProducer>* gbp,
                                     const sp<IBinder>& parentHandle, const sp<Layer>& parentLayer,
                                     uint32_t* outTransformHint) {
      ......
      case ISurfaceComposerClient::eFXSurfaceBufferQueue:
            result = createBufferQueueLayer(client, std::move(uniqueName), w, h, flags,
                                            std::move(metadata), format, handle, gbp, &layer);
      ......
}

Surface的操作

1 Surface操作简介

Surface对象后怎么就能拿到帧缓冲区的操作接口呢?我们来看Surface的实现:

public class Surface implements Parcelable {
    ......
    private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
            throws OutOfResourcesException;
    private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
    ......    
}

nativeLockCanvas这个方法对应的是出队dequeueBuffer,从队列中取到Buffer也就是画布;

nativeUnlockCanvasAndPost这个方法对应的是入队queueBuffer,将buffer提交到队列中去;

2 对画布操作

当我们接收到同步信号的时候会调用ViewRootImpl的performTraversals,最后会调用到drawSoftware,在这个函数中会拿到画布然后分发draw事件

 private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
            boolean scalingRequired, Rect dirty, Rect surfaceInsets){
     ......
     //拿到画布
	 canvas = mSurface.lockCanvas(dirty);
     ......
     //mView是DecorView向下分发事件
     mView.draw(canvas);
     ......
 }

在View的onDraw方法中,会将界面信息转化为RenderNode,类似于Html的Element。

public RenderNode updateDisplayListIfDirty() {
    ......
     final RecordingCanvas canvas = renderNode.beginRecording(width, height);//这里开始displaylist的record
     ......
     draw(canvas);
     ......
     
}

上面的RecordingCanvas就是扮演一个绘图指令的记录员角色,它会将这个View通过draw函数绘制的指令以displaylist形式记录下来。

在Android的设计里View会对应一个RenderNode, RenderNode里的一个重要数据结构是DisplayList, 每个DisplayList都会包含一系列DisplayListData. 这些DisplayList也会同样以树形结构组织在一起。

当UI线程完成它的绘制工作后,它工作的产物是一堆DisplayListData, 我们可以将其理解为是一堆绘图指令的集合,每一个DisplayListData都是在描绘这个View长什么样子,所以一个View树也可能理解为它的样子由对应的DisplayListData构成的树来描述:

在这里插入图片描述

DisplayListData

class DisplayListData final {
    ......
    void drawPath(const SkPath&, const SkPaint&);
    void drawRect(const SkRect&, const SkPaint&);
    void drawRegion(const SkRegion&, const SkPaint&);
    void drawOval(const SkRect&, const SkPaint&);
    void drawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&);
    ......
    template <typename T, typename... Args>
    void* push(size_t, Args&&...);
    ......
    SkAutoTMalloc<uint8_t> fBytes;
    ......
}

它的组成大体可以看成三个部分,第一部分是一堆以draw打头的函数,它们是最基本的绘图指令,比如画一条线, 画一个矩形,画一段圆弧等等, 第二部分是一个push模版函数,后面我们会看到它的作用; 第三个是一块存储区fBytes,它会根据需要放大存储区的大小。

通过上面的了解,我们知道了UI线程并没有将应用设计的View转换成像素点数据,而是将每个View的绘图指令存入了内存中,我们通常称这些绘图指令为DisplayList

3.提交画布内容

当所有的View的displaylist建立完成后

int RenderProxy::syncAndDrawFrame() {
    return mDrawFrameTask.drawFrame();
}
void DrawFrameTask::postAndWait() {
    AutoMutex _lock(mLock);
    mRenderThread->queue().post([this]() { run(); });//丢任务到RenderThread线程
    mSignal.wait(mLock);
}

这边可以看到UI线程的工作到此结束,它丢了一个叫DrawFrameTask的任务到RenderThread线程中去,之后画面绘制的工作转移到RenderThread中来

void DrawFrameTask::run() {
    .....
    context->draw();
    .....
}
void CanvasContext::draw() {
    ......
    Frame frame = mRenderPipeline->getFrame();//这句会调用到Surface的dequeueBuffer
    ......
     bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
                                      mContentDrawBounds, mOpaque, mLightInfo, mRenderNodes,
                                      &(profiler()));
    ......
    waitOnFences();
    ......
    bool didSwap =
            mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);//这句会调用到Surface的queueBuffer
    ......
}

在这个函数中完成了三个重要的动作,一个是通过getFrame调到了Surface的dequeueBuffer向SurfaceFlinger申请了画布, 第二是通过mRenderPipeline->draw将画面画到申请到的画布上, 第三是通过调mRenderPipeline->swapBuffers把画布提交到SurfaceFlinger去显示。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值