美文网首页Android系统方面那些事
Android9.0 硬件加速(三)-绑定Surface到Ren

Android9.0 硬件加速(三)-绑定Surface到Ren

作者: Stan_Z | 来源:发表于2019-04-03 21:46 被阅读308次

    原创文章,转载注明出处,多谢合作。

    接上篇,本篇了解下绑定Surface到RenderThread的过程.

    从ViewRootmpl的setView中的requestLayout()开始:

    @Override
    public void requestLayout() {
       if (!mHandlingLayoutInLayoutRequest) {
           checkThread();
    mLayoutRequested = true;
    scheduleTraversals();
       }
    }
    void scheduleTraversals() {
       if (!mTraversalScheduled) {
           mTraversalScheduled = true;
    mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
    mChoreographer.postCallback(
                   Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    if (!mUnbufferedInputDispatch) {
               scheduleConsumeBatchedInput();
    }
           notifyRendererOfFramePending();
    pokeDrawLockIfNeeded();
       }
    }
    

    接着看 mTraversalRunnable , 这是向Choreographer注册的postRunnable回调

    final class TraversalRunnable implements Runnable {
       @Override
    public void run() {
           doTraversal();
       }
    }
    
    void doTraversal() {
       if (mTraversalScheduled) {
           mTraversalScheduled = false;
    mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    if (mProfile) {
               Debug.startMethodTracing("ViewAncestor");
    }
           performTraversals();
    if (mProfile) {
               Debug.stopMethodTracing();
    mProfile = false;
    }
       }
    }
    

    performTraversals()正式开始UI处理流程

    private void performTraversals() {
    ...
    boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
    if (layoutRequested) {//满足重新layout的需求
    ...
          / /预测量阶段, 此阶段将会调用performMeasure计算出View树为显示其内容所需的尺寸,即期望的窗口尺寸.
      windowSizeMayChange |= measureHierarchy(host, lp, res,desiredWindowWidth, desiredWindowHeight);
    }
    ...
    / /根据预测量的结果,通过IWindowSession.relayout()方法向WMS请求调整窗口的尺寸等属性,这将引发WMS对窗口进行重新布局,并将布局结果返回给ViewRootImpl
    relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
    ...
    if (!hadSurface) {//首次冷启动hadSurface为 false
    if (mAttachInfo.mThreadedRenderer != null) { //之前ThreadedRenderer已经初始化好了
        hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface);
      }
    }
    ...
    if (!mStopped || mReportNextDraw) {
    performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);//以窗口的实际尺寸对View树进行最终测量
    }
    ...
    final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);//View树布局
    if (didLayout) {
       performLayout(lp, mWidth, mHeight);
    ...
    }
    ...
    boolean cancelDraw = mAttachInfo.mTreeObserver.dispatchOnPreDraw() || !isViewVisible;
    if (!cancelDraw && !newSurface) {
      ... 
      performDraw();//开始绘制处理
       ...
      }
    ...
    }
    

    这里surface绑定流程是从mThreadedRenderer.initialize开始的:

    /frameworks/base/core/java/android/view/ThreadedRenderer.java
    
    boolean initialize(Surface surface) throws OutOfResourcesException {
       boolean status = !mInitialized;
    mInitialized = true;
    updateEnabledState(surface);
    nInitialize(mNativeProxy, surface);
    return status;
    }
    

    updateEnabledState 设置了一个Enabled标记

    private void updateEnabledState(Surface surface) {
       if (surface == null || !surface.isValid()) {
           setEnabled(false); //首次启动走这
    } else {
           setEnabled(mInitialized);
    }
    }
    

    另外还有个nInitialize 它是个Native方法:

    /frameworks/base/core/jni/android_view_ThreadedRenderer.cpp
    
    static void android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
           jlong proxyPtr, jobject jsurface) {
       RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
       sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
       proxy->initialize(surface);
    }
    

    获取java层创建的Surface ,然后走RenderProxy initialize

    void RenderProxy::initialize(const sp<Surface>& surface) {
       mRenderThread.queue().post(
               [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf));
    ...
    });
    }
    

    这里mContext 是CanvasContext 由它执行 setSurface

    void CanvasContext::setSurface(sp<Surface>&& surface) {
       ATRACE_CALL(); //这里就是systrace中的setSurface label
       mNativeSurface = std::move(surface);
       ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb;
       bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode);
       mFrameNumber = -1;
       if (hasSurface) {
           mHaveNewSurface = true;
           mSwapHistory.clear();
       } else {
           mRenderThread.removeFrameCallback(this);
           mGenerationID++;
       }
    }
    

    上篇我们讲过, 9.0走的是SkiaGL , 因此mRenderPipeline对应的是SkiaOpenGLPipeline.

    frameworks/base/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
    
    bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
                                       ColorMode colorMode) {
       if (mEglSurface != EGL_NO_SURFACE) {
           mEglManager.destroySurface(mEglSurface);
           mEglSurface = EGL_NO_SURFACE;
       }
       if (surface) {
           const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
           mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
       }
       if (mEglSurface != EGL_NO_SURFACE) {
           const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
           mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
           return true;
       }
       return false;
    }
    

    接着看EglManager.createSurface方法

    frameworks/base/libs/hwui/renderthread/EglManager.cpp
    
    EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
       initialize();//创建EGLContext
       ...
       //通过eglCreateWindowSurface创建EGLSurface
       EGLSurface surface = eglCreateWindowSurface(
               mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
       ...
       return surface;
    }
    

    这个方法先看initialize()

    void EglManager::initialize() {
       if (hasEglContext()) return;
       ATRACE_NAME("Creating EGLContext");//对应systrace中的Creating EGLContext label
       ...
       loadConfigs();
       createContext();
       createPBufferSurface();
       makeCurrent(mPBufferSurface);
       DeviceInfo::initialize();
       mRenderThread.renderState().onGLContextCreated();
       if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
    #ifdef HWUI_GLES_WRAP_ENABLED
           debug::GlesDriver* driver = debug::GlesDriver::get();
           sk_sp<const GrGLInterface> glInterface(driver->getSkiaInterface());
    #else
    sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
    #endif
    LOG_ALWAYS_FATAL_IF(!glInterface.get());
           GrContextOptions options;
           options.fDisableDistanceFieldPaths = true;
           mRenderThread.cacheManager().configureContext(&options);
           sk_sp<GrContext> grContext(GrContext::MakeGL(std::move(glInterface), options));
           LOG_ALWAYS_FATAL_IF(!grContext.get());
           mRenderThread.setGrContext(grContext);
       }
    }
    

    这里主要是创建了EGLContext以及PBufferSurface.

    再回过头来看EglManager::createSurface的eglCreateWindowSurface部分,它简单说就是创建EGLSurface.
    再稍微跟下eglCreateWindowSurface这个方法:

    external/swiftshader/src/OpenGL/libEGL/main.cpp
    
    EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list)
    {
    return egl::CreateWindowSurface(dpy, config, window, attrib_list);
    }
    

    最后调用libEGL.cpp的CreateWindowSurface:

    external/swiftshader/src/OpenGL/libEGL/libEGL.cpp
    
    EGLSurface CreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType window, const EGLint *attrib_list)
    {
    TRACE("(EGLDisplay dpy = %p, EGLConfig config = %p, EGLNativeWindowType win = %p, "
    "const EGLint *attrib_list = %p)", dpy, config, window, attrib_list);
    egl::Display *display = egl::Display::get(dpy);
    if(!validateConfig(display, config))
    {
    return EGL_NO_SURFACE;
    }
    if(!display->isValidWindow(window))
    {
    return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
    }
    return display->createWindowSurface(window, config, attrib_list);
    }
    

    从这部分看,最终调用的是OpenGL库的方法了,这里暂时不求甚解,继续跟着主线走。

    注:
    EGLSurface: 它是一个 EGL 分配的离屏缓冲区 (称为 "pbuffer") 或由操作系统分配的窗口。由 eglCreateWindowSurface() 调用创建。接收一个 "窗口对象" 作为参数,在 Android 上它可以是一个 SurfaceView,SurfaceTexture,SurfaceHolder 或 Surface -- 所有在底层具有 BufferQueue 的东西。当你执行这个调用时,EGL 创建一个新的 EGLSurface 对象,将它与窗口对象的 BufferQueue 的生产者接口连接。从那时起,向那个 EGLSurface 渲染将使得一个缓冲区被取出,向其中渲染,并放回以由消费者使用。

    EGL创建EGLSurface有三个方法:eglCreateWindowSurface()、eglCreatePbufferSurface()和eglCreatePixmapSurface() 分别创建WindowSurface、PbufferSurface、PixmapSurface.

    • WindowSurface 在屏幕上的一块显示区的封装,渲染后即显示在界面上。
    • PbufferSurface 在显存中开辟一个空间,将渲染后的数据(帧)存放在这里。
    • PixmapSurface 以位图的形式存放在内存中,据说各平台的支持不是很好。

    OpenGL操作的最终目标实际上是帧缓存(Frame Buffer)后面的各种表现形式则是EGL对Frame Buffer的封装.

    最后总结一张流程图:


    绑定Surface到RenderThread整体流程

    相关文章

      网友评论

        本文标题:Android9.0 硬件加速(三)-绑定Surface到Ren

        本文链接:https://www.haomeiwen.com/subject/sqmtiqtx.html