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

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

接上篇,本篇了解下绑定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(proxyPtr);
   sp surface = android_view_Surface_getSurface(env, jsurface);
   proxy->initialize(surface);
}

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

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

这里mContext 是CanvasContext 由它执行 setSurface

void CanvasContext::setSurface(sp&& 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 glInterface(driver->getSkiaInterface());
#else
sk_sp glInterface(GrGLCreateNativeInterface());
#endif
LOG_ALWAYS_FATAL_IF(!glInterface.get());
       GrContextOptions options;
       options.fDisableDistanceFieldPaths = true;
       mRenderThread.cacheManager().configureContext(&options);
       sk_sp 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的封装.

最后总结一张流程图:


Android9.0 硬件加速(三)-绑定Surface到RenderThread_第1张图片
绑定Surface到RenderThread整体流程

你可能感兴趣的:(Android9.0 硬件加速(三)-绑定Surface到RenderThread)