theme: condensed-night-purple highlight: atom-one-dark
硬件渲染中采用AttachInfo的mThreadRenderer.draw方法传入view,attachinfo和ViewRootImpl开始硬件渲染。
代码语言:javascript复制private boolean draw(boolean fullRedrawNeeded) {
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
if (mAttachInfo.mThreadedRenderer != null && mAttachInfo.mThreadedRenderer.isEnabled()) {
// 硬件渲染
mAttachInfo.mThreadedRenderer.draw(mView, mAttachInfo, this);
} else {
// 软件渲染
}
}
}
ThreadRender的初始化
代码语言:javascript复制resume的时候会调用ViewRootImpl的setView方法创建windowSession和WMS通信,之后会调用enbleHardwareAccleration方法判断是否开启硬件渲染
>ViewRootImpl.java
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
// ...
else if (!ThreadedRenderer.sRendererDisabled
|| (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
// 进程默认 开启硬件绘制
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
// ...
}
}
>ThreadedRenderer.java
public static ThreadedRenderer create(Context context, boolean translucent, String name) {
ThreadedRenderer renderer = null;
if (isAvailable()) {
renderer = new ThreadedRenderer(context, translucent, name);
}
return renderer;
}
// 构造方法
ThreadedRenderer(Context context, boolean translucent, String name) {
// 调用父类的构造
super();
setName(name);
setOpaque(!translucent);
// ...
}
>HardwareRenderer.java
// 父类的构造
public HardwareRenderer() {
// 创建一个Java层的 根RootNode 节点
mRootNode = RenderNode.adopt(nCreateRootRenderNode());
mRootNode.setClipToBounds(false);
// 创建一个 native层的 RenderProxy 对象, 用来和RenderThread线程通信
mNativeProxy = nCreateProxy(!mOpaque, mRootNode.mNativeRenderNode);
if (mNativeProxy == 0) {
throw new OutOfMemoryError("Unable to create hardware renderer");
}
Cleaner.create(this, new DestroyContextRunnable(mNativeProxy));
// 往AMS设置 renderThread的线程tid
ProcessInitializer.sInstance.init(mNativeProxy);
}
public static RenderNode adopt(long nativePtr) {
//创建Java层的RenderNode, 持有native层的node 引用
return new RenderNode(nativePtr);
}
调用父类的构造方法流程如下:
- ncreateRootRenderNode会创建,native层的RootRenderNode对象,并设置node的name为RootRenderNode
- 接着创建一个Java层的根RootNode节点持有natve层的node引用
static jlong android_view_ThreadedRenderer_createProxy(JNIEnv* env, jobject clazz,
jboolean translucent, jlong rootRenderNodePtr) {
// 获取之前创建的 rootRenderNode
RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootRenderNodePtr);
// 创建 ContextFactoryImpl 对象
ContextFactoryImpl factory(rootRenderNode);
// new 一个 RenderProxy对象
RenderProxy* proxy = new RenderProxy(translucent, rootRenderNode, &factory);
return (jlong) proxy;
}
// RenderProxy 的构造函数
>frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory)
//mRenderThread 赋值。一个应用只会拥有一个RenderThread线程
: mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
//往RenderThread的队列中post一个消息创建CanvasContext对象
mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
// 在RenderThread线程中,创建CanvasContext对象。用于是链接OpenGL/Vulkan和graphicBuffer缓冲区的关键
//最终要使用这个contetx保存的surface的GraphBuffer进行渲染
return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
});
// mDrawFrameTask 设置context
mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode,
pthread_gettid_np(pthread_self()), getRenderThreadTid());
}
>frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
RenderNode* rootRenderNode, IContextFactory* contextFactory) {
// 根据渲染管道的配置
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
case RenderPipelineType::SkiaGL:
// skiaOpenGl渲染管道
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
case RenderPipelineType::SkiaVulkan:
// skiaVulkan渲染管道
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
default:
LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
return nullptr;
}
- nCreateProxy方法传入native的rootRenderNode,利用之前创建的rootRenderNode创建ContextFactoryImpl对象,紧接着创建一个RenderProxy对象(用于和)
- Renderproxy对象的构造函数中获取到RenderThread单例线程,然后在这个线程中去创建CanvasContext对象(链接OpenGL/Vulkan和graphicBuffer缓冲区的关键)。
RenderThread的第一个drawFrameTask任务就是去创建CanvasContext
创建过程会根据渲染管道配置去创建不同的canvascontext。t比如skiaOpenGl渲染管道还是skiaVulkan渲染管道;接着给drawFarmeTask设置上面创建的context。
- 将创建出来的RenderProxy传入到AMS中,也就是像AMS设置renderThread的线程tid
小结:
ThreadedRenderer 在ViewRootImpl的setView()中被初始化。构造方法做了如下初始化:
- 在构造方法中会创建Java和native层两个 根RenderNode节点。
- 创建native层的RenderProxy对象,持有 RenderThread 单例线程的引用。
- 给RenderThread线程,设置渲染的上下文。根据配置该CanvasContext采用的是管道:SkiaOpenGLPipeline 或者 SkiaVulkanPipeline。
Java层的都是renderNode节点对象,只有native层才可以创建rootRenderNode对象。在setView初始化的时候会创建native层的rootrenderNode之后创建一个rendernode绑定这个native的rootRenderNode
RenderNode
代码语言:javascript复制>View.java
public View(Context context) {
mContext = context;
mResources = context != null ? context.getResources() : null;
// ...
// 生成一个 RenderNode节点
mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this));
}
> RenderNode.java
/** @hide */
public static RenderNode create(String name, @Nullable AnimationHost animationHost) {
return new RenderNode(name, animationHost);
}
//构造方法
private RenderNode(String name, AnimationHost animationHost) {
// 调用native方法 生成
mNativeRenderNode = nCreate(name);
NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeRenderNode);
mAnimationHost = animationHost;
}
>frameworks/base/libs/hwui/jni/android_graphics_RenderNode.cpp
static jlong android_view_RenderNode_create(JNIEnv* env, jobject, jstring name) {
// 创建一个 renderNode节点
RenderNode* renderNode = new RenderNode();
renderNode->incStrong(0);
if (name != NULL) {
const char* textArray = env->GetStringUTFChars(name, NULL);
renderNode->setName(textArray);
env->ReleaseStringUTFChars(name, textArray);
}
return reinterpret_cast<jlong>(renderNode);
}
RenderNode有两个构造方法。一个是根View专用的接受native层的RootRenderNode对象;还有一个是普通的除了根View用的接受View名字的构造方法。第二种最终是调用的nCreate创建的c层的RenderNode绑定
RenderNode 是根据view树来建立的。每一个View对应一个RenderNode节点。
一个RenderNode节点包含了当前view的绘制命令drawOp( 如 drawLines->drawLinesOp), 同时还包括绘制子RenderNode节点的命令:DrawRenderNodeOp。因此,可看成一颗RenderNode树。 每一个drawXXXOp命令都有对应的OpenGL/Vulkan 命令与之对应。
RecordingCanvas
RecordingCanvas 用来记录 View树 中的硬件加速绘制动作drawOp。对应native层的 SkiaRecordingCanvas。 主要功能都是由 native来完成。 通过obtain()方法来获得一个 RecordingCanvas
obtain方法需要传入RenderNode对象和宽高信息来创建RecordingCanvas,第一次通过new创建之后进行修改器node宽高内部属性不再进行创建。RecordingCanvas构造方法中最终在c层创建了一个SkiaRecordingCanvas也就是和java层的RecordingCanvas对应。
ThreadedRenderer.draw()
代码语言:javascript复制void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
// 构建View的 drawXXXOp树
updateRootDisplayList(view, callbacks);
// 通知 RenderThread 线程 开始绘制
int syncResult = syncAndDrawFrame(choreographer.mFrameInfo);
}
updateRootDisplayList
代码语言:javascript复制> ThreadedRenderer.java
private void updateRootDisplayList(View view, DrawCallbacks callbacks) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Record View#draw()");
//构建View的drawXXXop树也就是displayList绘制命令
//更新传入view对应的 RenderNode中的displayList(drawOp树)
updateViewTreeDisplayList(view);
// ...
// 当根节点重绘时需要重新计算drawOp树
if (mRootNodeNeedsUpdate || !mRootNode.hasDisplayList()) {
// 从RecordingCanvas缓存池中,获取一个 RecordingCanvas 对象,包含了当前RenderNode、width、height信息
RecordingCanvas canvas = mRootNode.beginRecording(mSurfaceWidth, mSurfaceHeight);
try {
final int saveCount = canvas.save();
canvas.translate(mInsetLeft, mInsetTop);
callbacks.onPreDraw(canvas);
canvas.enableZ();
// 返回view对应的node,开始绘制RenderNode
canvas.drawRenderNode(view.updateDisplayListIfDirty());
canvas.disableZ();
callbacks.onPostDraw(canvas);
canvas.restoreToCount(saveCount);
mRootNodeNeedsUpdate = false;
} finally {
// 结束绘制,加入到Nodes集合
mRootNode.endRecording();
}
}
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
>RenderNode.java
public @NonNull RecordingCanvas beginRecording(int width, int height) {
// 一个 RenderNode节点 只能有一个 RecordingCanvas对象
if (mCurrentRecordingCanvas != null) {
throw new IllegalStateException(
"Recording currently in progress - missing #endRecording() call?");
}
mCurrentRecordingCanvas = RecordingCanvas.obtain(this, width, height);
return mCurrentRecordingCanvas;
}
updateViewTreeDisplayList 更新View树的DisplayList
代码语言:javascript复制private void updateViewTreeDisplayList(View view) {
view.mPrivateFlags |= View.PFLAG_DRAWN;
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
== View.PFLAG_INVALIDATED;
view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
// 调用了view的 updateDisplayListIfDirty
view.updateDisplayListIfDirty();
view.mRecreateDisplayList = false;
}
传入View获取到对应RenderNode中的displayList;如果根节点需要更新并且拥有drawOp命令需要获取到根节点的RecordingCanvas对象(包含当前node宽高信息)并调用drawRenderNode进行更新view的displayList( updateDisplayListIfDirty )最后调用rootnode的endRecording加入到nodes集合中
updateDisplayListIfDirty
代码语言:javascript复制public RenderNode updateDisplayListIfDirty() {
// 拿到对应的 renderNode
final RenderNode renderNode = mRenderNode;
if (!canHaveDisplayList()) {
// can't populate RenderNode, don't try
return renderNode;
}
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
|| !renderNode.hasDisplayList()
|| (mRecreateDisplayList)) {
// Don't need to recreate the display list, just need to tell our
// children to restore/recreate theirs
// 如果当前view的缓存可用,则重用drawOp展示列表。告知子view去重建displayList
if (renderNode.hasDisplayList()
&& !mRecreateDisplayList) {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
// 分发子view去 重建displayList
dispatchGetDisplayList();
return renderNode; // no work needed
}
int width = mRight - mLeft;
int height = mBottom - mTop;
int layerType = getLayerType();
// 如果走到这里表示缓存不可用需要drawOp树重建,开始记录drawOp
//获取RecordingCanvas后续draw的时候是绘制到这块canvas的
final RecordingCanvas canvas = renderNode.beginRecording(width, height);
try {
if (layerType == LAYER_TYPE_SOFTWARE) {
// 如果当前view拥有LAYER_TYPE_SOFTWARE类型,及时开了硬件加速,也只会使用
//Android软件渲染管道来绘制。
buildDrawingCache(true);
Bitmap cache = getDrawingCache(true);
if (cache != null) {
canvas.drawBitmap(cache, 0, 0, mLayerPaint);
}
} else {
// Fast path for layouts with no backgrounds
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
// 如果自身不需要绘制,则分发到子view,让子view去完成绘制
dispatchDraw(canvas);
drawAutofilledHighlight(canvas);
if (mOverlay != null && !mOverlay.isEmpty()) {
mOverlay.getOverlayView().draw(canvas);
}
if (debugDraw()) {
debugDrawFocus(canvas);
}
} else {
//查看下行代码解释
draw(canvas);
}
}
} finally {
// 结束记录drawOp
renderNode.endRecording();
setDisplayListProperties(renderNode);
}
} else {
mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
mPrivateFlags &= ~PFLAG_DIRTY_MASK;
}
return renderNode;
}
// draw 方法
public void draw(Canvas canvas) {
/*
* Draw traversal performs several drawing steps which must be executed
* in the appropriate order:
*
* 1. Draw the background
* 2. If necessary, save the canvas' layers to prepare for fading
* 3. Draw view's content
* 4. Draw children
* 5. If necessary, draw the fading edges and restore layers
* 6. Draw decorations (scrollbars for instance)
*/
}
}
和根View一样调用updateDisplayListIfDirty;如果当前View缓存可用则重用drawOp列表。分发子View去重建displayList;如果缓存不可用表示需要重建DrawOp树
重建DrawOp树的过程起始点
重建DrawOp树的过程起始点就是renderNode.beginRecording获取到RecordingCanvas记录绘制命令
重建DrawOp树记录绘制指令
调用 draw方法内部会将命令添加到RecordingCanvas(本质是native层的SkiaCanvas) 中(六个顺序背景,内容等)
重建DrawOp树结束将canvas记录的DisplayList返回给java层
代码语言:javascript复制> RenderNode.java
public void endRecording() {
if (mCurrentRecordingCanvas == null) {
throw new IllegalStateException(
"No recording in progress, forgot to call #beginRecording()?");
}
RecordingCanvas canvas = mCurrentRecordingCanvas;
mCurrentRecordingCanvas = null;
// 1 结束绘制动作记录,调用到native,返回native层的SkiaDisplayList对象的引用
long displayList = canvas.finishRecording();
//释放displayList
nSetDisplayList(mNativeRenderNode, displayList);
canvas.recycle();
}
> nSetDisplayList
> frameworks/base/core/jni/android_view_RenderNode.cpp
static void android_view_RenderNode_setDisplayList(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jlong displayListPtr) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
DisplayList* newData = reinterpret_cast<DisplayList*>(displayListPtr);
renderNode->setStagingDisplayList(newData);
}
> frameworks/base/libs/hwui/RenderNode.cpp
void RenderNode::setStagingDisplayList(DisplayList* displayList) {
//
mValid = (displayList != nullptr);
mNeedsDisplayListSync = true;
//释放之前的 displayList
delete mStagingDisplayList;
// 赋值新的 displayList
mStagingDisplayList = displayList;
}
RecordingCanvasrenderNode.endRecording()结束记录drawOP树 。 node调用endRecording(),内部最终调用的是native层的 SkiaRecordingCanvas的finishRecording()方法,返回 displayList对象的引用给java层。
DrawOp树重建总结
- 通过ThreadedRenderer.updateRootDisplayList(),根据view树来构建对应的RenderNode 树(一个view对应一个node) 。每个node中包含了当前view的绘制指令,如drawXXXop,如果有子view还会包含drawRenderNodeOp命令。 这些Op又称为统称为displayList。
- 调用node.beginRecording()开始记录,得到java层的RecordingCanvas 对象,同时得到native层的 SkiaRecordingCanvas对象当前view开始执行draw(canvas) ,以及自己的子view的draw(canvas)方法,最终都是调用canvas的api,记录到RecordingCanvas中
- 调用node.endRecording()结束绘制, RenderNode.endRecording()做了两件事:调用native层 SkiaRecordingCanvas的finishRecording(),结束记录,同时返回displayList的引用到java层
至此,所有的绘制指令都存储到了对应的node中。
canvas.drawRenderNode绘制Node
上一步中只是更新了所有RenderNodenode中的displayList,也就是完成了canvas.drawRenderNode(view.updateDisplayListIfDirty())中view.updateDisplayListIfDirty()的部分,接下来就是调用drawRenderNode来对displayList进行绘制
canva.drawNode本质上是调用native层的Skiacanvas的drawRenderNode方法
代码语言:javascript复制public void drawRenderNode(@NonNull RenderNode renderNode) {
// 其实就是调用native的 canvas->drawRenderNode(...
nDrawRenderNode(mNativeCanvasWrapper, renderNode.mNativeRenderNode);
}
>frameworks/base/core/jni/android_view_DisplayListCanvas.cpp
static void android_view_DisplayListCanvas_drawRenderNode(jlong canvasPtr, jlong renderNodePtr) {
Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr);
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
canvas->drawRenderNode(renderNode);
}
>frameworks/base/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
// mChildNodes 是 std::deque<RenderNodeDrawable>类型。
//把renderNode转换成drawable对象,创建一个 RenderNodeDrawable对象,存入队列中
mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
// 取出 RenderNodeDrawable 对象
//RenderNodeDrawable 封装了一个node对象,让node可以被记录为 一系列的 skia 绘制命令。
auto& renderNodeDrawable = mDisplayList->mChildNodes.back();
// 开始绘制
drawDrawable(&renderNodeDrawable);
// use staging property, since recording on UI thread
if (renderNode->stagingProperties().isProjectionReceiver()) {
mDisplayList->mProjectionReceiver = &renderNodeDrawable;
}
}
// 开始绘制
>frameworks/base/libs/hwui/SkiaCanvas.h
void drawDrawable(SkDrawable* drawable) {
//mCanvas 是 SKCanvas对象
mCanvas->drawDrawable(drawable);
}
// 此时已经到了skia引擎库
>external/skia/src/core/SkCanvas.cpp
void SkCanvas::drawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
// 继续调用
this->onDrawDrawable(dr, matrix);
}
void SkCanvas::onDrawDrawable(SkDrawable* dr, const SkMatrix* matrix) {
// drawable bounds are no longer reliable (e.g. android displaylist)
// so don't use them for quick-reject
if (this->predrawNotify()) {
this->topDevice()->drawDrawable(this, dr, matrix);
}
}
SkBaseDevice* SkCanvas::topDevice() const {
SkASSERT(fMCRec->fDevice);
return fMCRec->fDevice;
}
topDevice() 返回的是 SkDevice对象。
>external/skia/src/core/SkDevice.cpp
void SkBaseDevice::drawDrawable(SkCanvas* canvas, SkDrawable* drawable, const SkMatrix* matrix) {
//able是 SKDrawable类型,上面传入的具体实现类是 RenderNodeDrawable
drawable->draw(canvas, matrix);
}
> external/skia/src/core/SkDrawable.cpp
void SkDrawable::draw(SkCanvas* canvas, const SkMatrix* matrix) {
SkAutoCanvasRestore acr(canvas, true);
if (matrix) {
//结合skia的 matrix
canvas->concat(*matrix);
}
// onDraw是一个抽象方法,具体实现的是xxxDrawable,而这里传入的是 RenderNodeDrawable
this->onDraw(canvas);
if ((false)) {
draw_bbox(canvas, this->getBounds());
}
}
RenderNodeDrawable
>frameworks/base/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
void RenderNodeDrawable::onDraw(SkCanvas* canvas) {
// negative and positive Z order are drawn out of order, if this render node drawable is in
// a reordering section
if ((!mInReorderingSection) || MathUtils::isZero(mRenderNode->properties().getZ())) {
this->forceDraw(canvas);
}
}
void RenderNodeDrawable::forceDraw(SkCanvas* canvas) const {
RenderNode* renderNode = mRenderNode.get();
//最重要的是这句,将displayList转换为SkiaDl语法
SkiaDisplayList* displayList = renderNode->getDisplayList().asSkiaDl();
displayList->mProjectedOutline = nullptr;
}
renderNode转换成RenderNodeDrawable对象
将renderNode转换成drawable对象创建一个RenderNodeDrawable对象,存入队列中
RenderNodeDrawable 封装了一个node对象,让node可以被记录为 一系列的 skia 绘制命令。
RenderNodeDrawable中将node转换成skia命令
这时候已经到了SkiaCanvas内部,调用SkCanvas的drawAble所有的绘制DrawOp命令最后都会转换成skia绘制命令
DrawFrameTask::drawFrame()
接着就开始进入到同步过程了。把renderNode同步到渲染线程也就是调用renderProxy的syncAndDrawFrame,其内部会调用mDrawFrameTask.drawFrame方法
代码语言:javascript复制// post到 RenderTHread 线程
postAndWait();其最后会调用到下一行:
//往渲染线程的队列中 post任务进去 ,回调run方法。
mRenderThread->queue().post([this]() { run(); });
也就是会往RenderThread的队列中post自己,最后会调用DrawFrmaeTask的run方法。
代码语言:javascript复制// run方法:
void DrawFrameTask::run() {
bool canUnblockUiThread;
bool canDrawThisFrame;
{
// 构造一个 treeInfo 对象
TreeInfo info(TreeInfo::MODE_FULL, *mContext);
// 遍历renderNode结合,转变为TreeInfo 信息
canUnblockUiThread = syncFrameState(info);
}
//赋值 CanvasContext 对象
CanvasContext* context = mContext;
// ...
nsecs_t dequeueBufferDuration = 0;
if (CC_LIKELY(canDrawThisFrame)) {
// 调用canvasContext的draw方法开始绘制
dequeueBufferDuration = context->draw();
}
}
//syncFrameState方法
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
// 准备eglcontext 上下文,用来链接OpenGL和 GraphicBuffer之间的桥梁
bool canDraw = mContext->makeCurrent();
for (size_t i = 0; i < mLayers.size(); i ) {
mLayers[i]->apply();
}
}
// makeCurrent()方法的具体实现为 SkiaOpenGLPipeline或者 SkiaVulkanPipeline。
>frameworks/base/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
// 调用 mEglManager 来初始化
if (!mEglManager.makeCurrent(mEglSurface, &error)) {
return MakeCurrentResult::AlreadyCurrent;
}
return error ? MakeCurrentResult::Failed : MakeCurrentResult::Succeeded;
}
>frameworks/base/libs/hwui/renderthread/EglManager.cpp
bool EglManager::makeCurrent(EGLSurface surface, EGLint* errOut, bool force) {
if (!force && isCurrent(surface)) return false;
if (surface == EGL_NO_SURFACE) {
// Ensure we always have a valid surface & context
// 确保surface有效
surface = mPBufferSurface;
}
//egl模块给OpenGL提供Surface和eglContext
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
...
}
return true;
}
run方法中会创建一个TreeInfo对象遍历renderNode转换成TreeInfo,接着调用makeCurrent初始化eglContext上下文(用来链接opengl和graphicbuffer的桥梁),主要是绑定surface让egl模块给opengl提供surface窗口和eglcontext上下文。通过EglManager的 makeCurrent()终于让OpenGL和本地窗口surface 联系了起来。因此,通过CanvasContext.draw() 就可以实现OpenGL/Vulkan绘制,最终通过Skia/Vulkan 引擎(SkiaOpenGLPipeline/SkiaVulkanPipeline)把数据渲染到缓冲区GraphicBuffer中
CanvasContext介绍
CanvasContext 作用:用于管理当前绘制区域。每个RenderThread对象有一个 CanvasContext。 管理全局EGL context和当前绘制区域surface。
绑定Surface
在ViewRootImpl的 setView方法,如果是硬件绘制则会请求Buffer,通过mAttachInfo.mThreadRender.alloateBuffers()
代码语言:javascript复制//mAttachInfo.mThreadRender.alloateBuffers
public void allocateBuffers() {
// JNI方法
nAllocateBuffers(mNativeProxy);
}
private static native void nAllocateBuffers(long nativeProxy);
>frameworks/base/core/jni/android_view_ThreadedRenderer.cpp
static void android_view_ThreadedRenderer_allocateBuffers(JNIEnv* env, jobject clazz,jlong proxyPtr) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
//调用RenderProxy的allocateBuffers
proxy->allocateBuffers();
}
>frameworks/base/libs/hwui/renderthread/RenderProxy.cpp
void RenderProxy::allocateBuffers() {
// post到renderThread线程中
//run方法中会调用CanvasContext.allocateBuffers()
mRenderThread.queue().post([=]() { mContext->allocateBuffers(); });
}
>frameworks/base/libs/hwui/renderthread/CanvasContext.cpp
void CanvasContext::allocateBuffers() {
if (mNativeSurface && Properties::isDrawingEnabled()) {
// ANativeWindow的hook方法
ANativeWindow_tryAllocateBuffers(mNativeSurface->getNativeWindow());
}
}
void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) {
if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
return;
}
// 最后调用到 ANativeWindow的perform函数,surface的hook_perform钩子函数也会回调
window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS);
}
在 Surface 中会进行申请buffer最终还是和软件绘制一样buffer是通过GraphBufferProducer进行申请的。请求到buffer后会调用ThreadProxy的init方法调用context.setSurface完成canvascontext和Surface的绑定