日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

renderthread是什么_Android5.0中 hwui 中 RenderThread 工作流程

發布時間:2023/12/3 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 renderthread是什么_Android5.0中 hwui 中 RenderThread 工作流程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

本篇文章是自己的一個學習筆記,記錄了 Android 5.0 中 hwui 中的 RenderThread 的簡單工作流程。由于是學習筆記,所以其中一些細節不會太詳細,我只是將大概的流程走一遍,將其工作流標注出來,下次遇到問題的時候就可以知道去哪里查。

下圖是我用 Systrace 抓取的一個應用啟動的時候 RenderThread 的第一次 Draw 的 Trace 圖,從這里面的順序來看 RenderThread 的流程。熟悉應用啟動流程的話應該知道,只有當第一次 DrawFrame 完成之后,整個應用的界面才會顯示在手機上,在這之前,用戶看到的是應用的 StartingWindow 的界面。

RenderThread Draw first frame

從Java層說起

應用程序的每一幀是從接收到 VSYNC 信號開始進行計算和繪制的,這要從 Choreographer 這個類說起了,不過由于篇幅原因,我們直接看一幀的繪制調用關系鏈即可:

繪制關系鏈

Choreographer 的 drawFrame 會調用到 ViewRootImpl 的 performTraversals 方法,而 performTraversals 方法最終會調用到performDraw() 方法, performDraw 又會調用到 draw(boolean fullRedrawNeeded) 方法,這個 draw 方法是 ViewRootImpl 的私有方法,和我們熟知的那個draw并不是同一個方法

if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {

mIsAnimating = false;

boolean invalidateRoot = false;

if (mHardwareYOffset != yOffset || mHardwareXOffset != xOffset) {

mHardwareYOffset = yOffset;

mHardwareXOffset = xOffset;

mAttachInfo.mHardwareRenderer.invalidateRoot();

}

mResizeAlpha = resizeAlpha;

dirty.setEmpty();

mBlockResizeBuffer = false;

mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);

}

如果是走硬件繪制路線的話,則會走這一條先,之后就會調用 mHardwareRenderer 的 draw 方法,這里的 mHardwareRenderer 指的是 ThreadedRenderer ,其 Draw 函數如下:

@Override

void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {

attachInfo.mIgnoreDirtyState = true;

long frameTimeNanos = mChoreographer.getFrameTimeNanos();

attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;

long recordDuration = 0;

if (mProfilingEnabled) {

recordDuration = System.nanoTime();

}

updateRootDisplayList(view, callbacks);

if (mProfilingEnabled) {

recordDuration = System.nanoTime() - recordDuration;

}

attachInfo.mIgnoreDirtyState = false;

// register animating rendernodes which started animating prior to renderer

// creation, which is typical for animators started prior to first draw

if (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 don't need this anymore as subsequent calls to

// ViewRootImpl#attachRenderNodeAnimator will go directly to us.

attachInfo.mPendingAnimatingRenderNodes = null;

}

int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,

recordDuration, view.getResources().getDisplayMetrics().density);

if ((syncResult & SYNC_INVALIDATE_REQUIRED) != 0) {

attachInfo.mViewRootImpl.invalidate();

}

}

這個函數里面的 updateRootDisplayList(view, callbacks) ;即 getDisplayList 操作。接下來就是比較重要的一個操作:

int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,

recordDuration, view.getResources().getDisplayMetrics().density);

可以看出這是一個阻塞操作,等Native層完成后,拿到返回值后才會進行下一步的操作。

Native層

其Native代碼在android_view_ThreadedRenderer.cpp中,對應的實現代碼如下:

static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,

jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {

RenderProxy* proxy = reinterpret_cast(proxyPtr);

return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);

}

RenderProxy的路徑位于frameworks/base/libs/hwui/renderthread/RenderProxy.cpp

int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,

float density) {

mDrawFrameTask.setDensity(density);

return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);

}

其中 mDrawFrameTask 是一個 DrawFrameTask 對象,其路徑位于frameworks/base/libs/hwui/renderthread/DrawFrameTask.cpp,其中drawFrame代碼:

int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {

mSyncResult = kSync_OK;

mFrameTimeNanos = frameTimeNanos;

mRecordDurationNanos = recordDurationNanos;

postAndWait();

// Reset the single-frame data

mFrameTimeNanos = 0;

mRecordDurationNanos = 0;

return mSyncResult;

}

其中 postAndWait() 的實現如下:

void DrawFrameTask::postAndWait() {

AutoMutex _lock(mLock);

mRenderThread->queue(this);

mSignal.wait(mLock);

}

就是將一個 DrawFrameTask 放入到了 mRenderThread 中,其中 queue 方法實現如下:

void RenderThread::queue(RenderTask* task) {

AutoMutex _lock(mLock);

mQueue.queue(task);

if (mNextWakeup && task->mRunAt < mNextWakeup) {

mNextWakeup = 0;

mLooper->wake();

}

}

其中 mQueue 是一個 TaskQueue 對象,其

void TaskQueue::queue(RenderTask* task) {

// Since the RenderTask itself forms the linked list it is not allowed

// to have the same task queued twice

LOG_ALWAYS_FATAL_IF(task->mNext || mTail == task, "Task is already in the queue!");

if (mTail) {

// Fast path if we can just append

if (mTail->mRunAt <= task->mRunAt) {

mTail->mNext = task;

mTail = task;

} else {

// Need to find the proper insertion point

RenderTask* previous = 0;

RenderTask* next = mHead;

while (next && next->mRunAt <= task->mRunAt) {

previous = next;

next = next->mNext;

}

if (!previous) {

task->mNext = mHead;

mHead = task;

} else {

previous->mNext = task;

if (next) {

task->mNext = next;

} else {

mTail = task;

}

}

}

} else {

mTail = mHead = task;

}

}

接著看 RenderThread 之前的 queue 方法,

void Looper::wake() {

ssize_t nWrite;

do {

nWrite = write(mWakeWritePipeFd, "W", 1);

} while (nWrite == -1 && errno == EINTR);

if (nWrite != 1) {

if (errno != EAGAIN) {

ALOGW("Could not write wake signal, errno=%d", errno);

}

}

}

wake 函數則更為簡單,僅僅向管道的寫端寫入一個字符“W”,這樣管道的讀端就會因為有數據可讀而從等待狀態中醒來。

HWUI-RenderThread

接下來會到哪里去,我們首先要熟悉一下RenderThread,RenderThread是繼承自Thread的,這個Thread是utils/Thread.h,RenderThread的初始化函數

RenderThread::RenderThread() : Thread(true), Singleton()

, mNextWakeup(LLONG_MAX)

, mDisplayEventReceiver(0)

, mVsyncRequested(false)

, mFrameCallbackTaskPending(false)

, mFrameCallbackTask(0)

, mRenderState(NULL)

, mEglManager(NULL) {

mFrameCallbackTask = new DispatchFrameCallbacks(this);

mLooper = new Looper(false);

run("RenderThread");

}

其 run 方法在 Thread 中有說明:

// Start the thread in threadLoop() which needs to be implemented.

virtual status_t run( const char* name = 0,

int32_t priority = PRIORITY_DEFAULT,

size_t stack = 0);

即啟動 threadLoop 函數,我們來看 RenderThread 的 threadLoop 函數,這個函數比較重要:

bool RenderThread::threadLoop() {

#if defined(HAVE_PTHREADS)

setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);

#endif

initThreadLocals();

int timeoutMillis = -1;

for (;;) {

int result = mLooper->pollOnce(timeoutMillis);

LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,

"RenderThread Looper POLL_ERROR!");

nsecs_t nextWakeup;

// Process our queue, if we have anything

while (RenderTask* task = nextTask(&nextWakeup)) {

task->run();

// task may have deleted itself, do not reference it again

}

if (nextWakeup == LLONG_MAX) {

timeoutMillis = -1;

} else {

nsecs_t timeoutNanos = nextWakeup - systemTime(SYSTEM_TIME_MONOTONIC);

timeoutMillis = nanoseconds_to_milliseconds(timeoutNanos);

if (timeoutMillis < 0) {

timeoutMillis = 0;

}

}

if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {

drainDisplayEventQueue(true);

mFrameCallbacks.insert(

mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());

mPendingRegistrationFrameCallbacks.clear();

requestVsync();

}

}

return false;

}

可以看到,一個 for 循環是一個無限循環,而其中 pollOnce 是一個阻塞函數,直到我們上面調用了 mLooper->wake() 之后,會繼續往下走,走到 while 循環中:

while (RenderTask* task = nextTask(&nextWakeup)) {

task->run();

// task may have deleted itself, do not reference it again

}

會將 RenderTask 取出來執行其 run 方法,經過前面的流程我們知道這個 RenderTask 是一個 DrawFrameTask ,其run方法如下:

void DrawFrameTask::run() {

ATRACE_NAME("DrawFrame");

mContext->profiler().setDensity(mDensity);

mContext->profiler().startFrame(mRecordDurationNanos);

bool canUnblockUiThread;

bool canDrawThisFrame;

{

TreeInfo info(TreeInfo::MODE_FULL, mRenderThread->renderState());

canUnblockUiThread = syncFrameState(info);

canDrawThisFrame = info.out.canDrawThisFrame;

}

// Grab a copy of everything we need

CanvasContext* context = mContext;

// From this point on anything in "this" is *UNSAFE TO ACCESS*

if (canUnblockUiThread) {

unblockUiThread();

}

if (CC_LIKELY(canDrawThisFrame)) {

context->draw();

}

if (!canUnblockUiThread) {

unblockUiThread();

}

}

RenderThread.DrawFrame

上面說到了 DrawFrameTask 的 run 方法,這里 run 方法中的執行的方法即我們在最前面那張圖中所示的部分(即文章最前面那張圖),下面的流程就是那張圖中的函數調用,我們結合代碼和圖,一部分一部分來走整個 DrawFrame 的流程:

1. syncFrameState

第一個比較重要的函數是 syncFrameState ,從函數名就可以知道, syncFrameState 的作用就是同步 frame 信息,將 Java 層維護的 frame 信息同步到 RenderThread中。

Main Thread 和Render Thread 都各自維護了一份應用程序窗口視圖信息。各自維護了一份應用程序窗口視圖信息的目的,就是為了可以互不干擾,進而實現最大程度的并行。其中,Render Thread維護的應用程序窗口視圖信息是來自于 Main Thread 的。因此,當Main Thread 維護的應用程序窗口信息發生了變化時,就需要同步到 Render Thread 去。

所以查看代碼就可以知道有兩個 RenderNode,一個在 hwui 中,一個在 View 中。簡單來說,同步信息就是將 Java 層的 RenderNode 中的信息同步到 hwui 中的 RenderNode 中。 注意syncFrameState的返回值賦給了 canUnblockUiThread ,從名字可以看出這個 canUnblockUiThread 的作用是判斷是否喚醒 Main Thread ,也就是說如果返回為 true 的話,會提前喚醒主線程來執行其他的事情,而不用等到 draw 完成后再去喚醒 Main Thread。 這也是 Android 5.0 和 Android 4.x 最大的區別了。

syncFrameState

bool DrawFrameTask::syncFrameState(TreeInfo& info) {

mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);

mContext->makeCurrent();

Caches::getInstance().textureCache.resetMarkInUse();

for (size_t i = 0; i < mLayers.size(); i++) {

mContext->processLayerUpdate(mLayers[i].get());

}

mLayers.clear();

mContext->prepareTree(info);

if (info.out.hasAnimations) {

if (info.out.requiresUiRedraw) {

mSyncResult |= kSync_UIRedrawRequired;

}

}

// If prepareTextures is false, we ran out of texture cache space

return info.prepareTextures;

}

首先是makeCurrent,這里的mContext是一個CanvasContext對象,其makeCurrent實現如下:

void CanvasContext::makeCurrent() {

// In the meantime this matches the behavior of GLRenderer, so it is not a regression

mHaveNewSurface |= mEglManager.makeCurrent(mEglSurface);

}

mEglManager是一個EglManager對象,其實現為:

bool EglManager::makeCurrent(EGLSurface surface) {

if (isCurrent(surface)) return false;

if (surface == EGL_NO_SURFACE) {

// If we are setting EGL_NO_SURFACE we don't care about any of the potential

// return errors, which would only happen if mEglDisplay had already been

// destroyed in which case the current context is already NO_CONTEXT

TIME_LOG("eglMakeCurrent", eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));

} else {

EGLBoolean success;

TIME_LOG("eglMakeCurrent", success = eglMakeCurrent(mEglDisplay, surface, surface, mEglContext));

if (!success) {

LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",

(void*)surface, egl_error_str());

}

}

mCurrentSurface = surface;

return true;

}

這里會判斷mCurrentSurface == surface,如果成立,則不用再初始化操作,如果是另外一個surface。,則會執行eglMakeCurrent,來重新創建上下文。

makeCurrent之后,會調用mContext->prepareTree(info),其實現如下:

void CanvasContext::prepareTree(TreeInfo& info) {

mRenderThread.removeFrameCallback(this);

info.damageAccumulator = &mDamageAccumulator;

info.renderer = mCanvas;

if (mPrefetechedLayers.size() && info.mode == TreeInfo::MODE_FULL) {

info.canvasContext = this;

}

mAnimationContext->startFrame(info.mode);

mRootRenderNode->prepareTree(info);

mAnimationContext->runRemainingAnimations(info);

if (info.canvasContext) {

freePrefetechedLayers();

}

int runningBehind = 0;

// TODO: This query is moderately expensive, investigate adding some sort

// of fast-path based off when we last called eglSwapBuffers() as well as

// last vsync time. Or something.

TIME_LOG("nativeWindowQuery", mNativeWindow->query(mNativeWindow.get(),

NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind));

info.out.canDrawThisFrame = !runningBehind;

if (info.out.hasAnimations || !info.out.canDrawThisFrame) {

if (!info.out.requiresUiRedraw) {

// If animationsNeedsRedraw is set don't bother posting for an RT anim

// as we will just end up fighting the UI thread.

mRenderThread.postFrameCallback(this);

}

}

}

其中 mRootRenderNode->prepareTree(info) 又是最重要的。回到Java層,我們知道 ThreadedRenderer 在初始化時,初始化了一個指針

long rootNodePtr = nCreateRootRenderNode();

這個RootRenderNode也就是一個根Node,

mRootNode = RenderNode.adopt(rootNodePtr);

然后會創建一個 mNativeProxy 指針,在 Native 層初始化一個 RenderProxy 對象,將 rootNodePtr 傳給 RenderProxy 對象,這樣在 RenderProxy 我們就可以得到這個對象的指針了。其中 CanvasContext 也是在 RenderProxy 對象初始化的時候被初始化的,初始化的時候將 rootNodePtr 傳給了 CanvasContext 對象。

我們之前提到 ThreadedRenderer 的 draw 方法中首先會調用updateRootDisplayList,即我們熟悉的 getDisplayList 。這個方法中,其實也分為兩個步驟,第一個步驟是 updateViewTreeDisplayList,第二個步驟是將根 Node 加入到 DrawOp 中:

canvas.insertReorderBarrier();

canvas.drawRenderNode(view.getDisplayList());

canvas.insertInorderBarrier();

其最終實現在

status_t DisplayListRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t flags) {

LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");

// dirty is an out parameter and should not be recorded,

// it matters only when replaying the display list

DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(renderNode, flags, *currentTransform());

addRenderNodeOp(op);

return DrawGlInfo::kStatusDone;

}

再回到我們之前的 CanvasContext.prepareTree 中提到的 mRootRenderNode->prepareTree(info),這時候這里的 mRootRenderNode 就是 CanvasContext 初始化是傳進來的。

其實現在 RenderNode.cpp 中:

void RenderNode::prepareTree(TreeInfo& info) {

prepareTreeImpl(info);

}

void RenderNode::prepareTreeImpl(TreeInfo& info) {

TT_START_MARK(getName());

info.damageAccumulator->pushTransform(this);

if (info.mode == TreeInfo::MODE_FULL) {

pushStagingPropertiesChanges(info); //同步當前正在處理的Render Node的Property

}

uint32_t animatorDirtyMask = 0;

if (CC_LIKELY(info.runAnimations)) {

animatorDirtyMask = mAnimatorManager.animate(info);//執行動畫相關的操作

}

prepareLayer(info, animatorDirtyMask);

if (info.mode == TreeInfo::MODE_FULL) {

pushStagingDisplayListChanges(info); //同步當前正在處理的Render Node的Display List

}

prepareSubTree(info, mDisplayListData); //同步當前正在處理的Render Node的Display List引用的Bitmap,以及當前正在處理的Render Node的子Render Node的Display List等信息

pushLayerUpdate(info); //檢查當前正在處理的Render Node是否設置了Layer。如果設置了的話,就對這些Layer進行處理

info.damageAccumulator->popTransform();

TT_END_MARK();

}

這里所涉及到的進一步的具體操作大家可以自行去看代碼。

2. draw

Draw

執行完syncFrameState之后,接下來就是執行draw

if (CC_LIKELY(canDrawThisFrame)) {

context->draw();

}

CanvasContext的draw函數是一個核心函數,其位置在 frameworks/base/libs/hwui/OpenGLRenderer.cpp ,其實現如下:

void CanvasContext::draw() {

profiler().markPlaybackStart();

SkRect dirty;

mDamageAccumulator.finish(&dirty);

......

status_t status;

if (!dirty.isEmpty()) {

status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,

dirty.fRight, dirty.fBottom, mOpaque);

} else {

status = mCanvas->prepare(mOpaque);

}

Rect outBounds;

status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);

profiler().draw(mCanvas);

mCanvas->finish();

profiler().markPlaybackEnd();

if (status & DrawGlInfo::kStatusDrew) {

swapBuffers();

}

profiler().finishFrame();

/// M: enable to get overdraw count

if (CC_UNLIKELY(g_HWUI_debug_overdraw)) {

if (!mDebugOverdrawLayer) {

mDebugOverdrawLayer = LayerRenderer::createRenderLayer(mRenderThread.renderState(),

mCanvas->getWidth(), mCanvas->getHeight());

} else if (mDebugOverdrawLayer->layer.getWidth() != mCanvas->getWidth() ||

mDebugOverdrawLayer->layer.getHeight() != mCanvas->getHeight()) {

if (!LayerRenderer::resizeLayer(mDebugOverdrawLayer, mCanvas->getWidth(), mCanvas->getHeight())) {

LayerRenderer::destroyLayer(mDebugOverdrawLayer);

mDebugOverdrawLayer = NULL;

}

}

......

}

2.1 eglBeginFrame

首先來看eglBeginFrame的實現

void EglManager::beginFrame(EGLSurface surface, EGLint* width, EGLint* height) {

makeCurrent(surface);

if (width) {

eglQuerySurface(mEglDisplay, surface, EGL_WIDTH, width);

}

if (height) {

eglQuerySurface(mEglDisplay, surface, EGL_HEIGHT, height);

}

eglBeginFrame(mEglDisplay, surface);

}

makeCurrent是用來管理上下文,eglBeginFrame主要是校驗參數的合法性。

2.2 prepareDirty

status_t status;

if (!dirty.isEmpty()) {

status = mCanvas->prepareDirty(dirty.fLeft, dirty.fTop,

dirty.fRight, dirty.fBottom, mOpaque);

} else {

status = mCanvas->prepare(mOpaque);

}

這里的mCanvas是一個OpenGLRenderer對象,其prepareDirty實現

//TODO:增加函數功能描述

status_t OpenGLRenderer::prepareDirty(float left, float top,

float right, float bottom, bool opaque) {

setupFrameState(left, top, right, bottom, opaque);

// Layer renderers will start the frame immediately

// The framebuffer renderer will first defer the display list

// for each layer and wait until the first drawing command

// to start the frame

if (currentSnapshot()->fbo == 0) {

syncState();

updateLayers();

} else {

return startFrame();

}

return DrawGlInfo::kStatusDone;

}

2.3 drawRenderNode

Rect outBounds;

status |= mCanvas->drawRenderNode(mRootRenderNode.get(), outBounds);

接下來就是調用OpenGLRenderer的drawRenderNode方法進行繪制

status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int32_t replayFlags) {

status_t status;

// All the usual checks and setup operations (quickReject, setupDraw, etc.)

// will be performed by the display list itself

if (renderNode && renderNode->isRenderable()) {

// compute 3d ordering

renderNode->computeOrdering();

if (CC_UNLIKELY(mCaches.drawDeferDisabled)) { //判斷是否不重排序

status = startFrame();

ReplayStateStruct replayStruct(*this, dirty, replayFlags);

renderNode->replay(replayStruct, 0);

return status | replayStruct.mDrawGlStatus;

}

// 需要重新排序

bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs!

DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw);

DeferStateStruct deferStruct(deferredList, *this, replayFlags);

renderNode->defer(deferStruct, 0); //遞歸進行重排操作

flushLayers(); // 首先執行設置了 Layer 的子 Render Node 的繪制命令,以便得到一個對應的FBO

status = startFrame(); //執行一些諸如清理顏色繪沖區等基本操作

status = deferredList.flush(*this, dirty) | status;

return status;

}

// Even if there is no drawing command(Ex: invisible),

// it still needs startFrame to clear buffer and start tiling.

return startFrame();

}

這里的 renderNode 是一個 Root Render Node,

可以看到,到了這里雖然只是開始,但是其實已經結束了,這個函數里面最重要的幾步:

renderNode->defer(deferStruct, 0); //進行重排序

flushLayers(); 首先執行設置了 Layer 的子 Render Node 的繪制命令,以便得到一個對應的FBO

status = deferredList.flush(*this, dirty) | status; //對deferredList中的繪制命令進行真正的繪制操作

這幾個是渲染部分真正的核心部分,其中的代碼細節需要自己去研究。老羅在這部分講的很細,有空可以去看看他的文章Android應用程序UI硬件加速渲染的Display List渲染過程分析.

2.4 swapBuffers

if (status & DrawGlInfo::kStatusDrew) {

swapBuffers();

}

其核心就是調用EGL的 eglSwapBuffers(mEglDisplay, surface), duration)函數。

2.5 FinishFrame

profiler().finishFrame();

主要是記錄時間信息。

總結

鑒于我比較懶,而且總結能力不如老羅,就直接把他的總結貼過來了。

RenderThread的總的流程如下:

將Main Thread維護的Display List同步到Render Thread維護的Display List去。這個同步過程由Render Thread執行,但是Main Thread會被阻塞住。

如果能夠完全地將Main Thread維護的Display List同步到Render Thread維護的Display List去,那么Main Thread就會被喚醒,此后Main Thread和Render Thread就互不干擾,各自操作各自內部維護的Display List;否則的話,Main Thread就會繼續阻塞,直到Render Thread完成應用程序窗口當前幀的渲染為止。

Render Thread在渲染應用程序窗口的Root Render Node的Display List之前,首先將那些設置了Layer的子Render Node的Display List渲染在各自的一個FBO上,接下來再一起將這些FBO以及那些沒有設置Layer的子Render Node的Display List一起渲染在Frame Buffer之上,也就是渲染在從Surface Flinger請求回來的一個圖形緩沖區上。這個圖形緩沖區最終會被提交給Surface Flinger合并以及顯示在屏幕上。

第2步能夠完全將Main Thread維護的Display List同步到Render Thread維護的Display List去很關鍵,它使得Main Thread和Render Thread可以并行執行,這意味著Render Thread在渲染應用程序窗口當前幀的Display List的同時,Main Thread可以去準備應用程序窗口下一幀的Display List,這樣就使得應用程序窗口的UI更流暢。

注意最后一段,在 Android 4.x 時代,沒有RenderThread的時代,只有 Main Thread ,也就是說 必須要等到 Draw 完成后,才會去準備下一幀的數據,如下圖:

Paste_Image.png

Android5.0 之后,如老羅所說,有兩種情況,

Main Thread 和 Render Thread

Render Thread 提前喚醒了 Main Thread

可以看到第二張圖中,Render Thread 并沒有繪制完成,但是由于其提前喚醒了 Main Thread ,所以 Main Thread 在下一個Vsync信號到來的時候,響應了Vsync事件,開始準備下一幀。

此時雖然由于第一幀繪制時間過長,導致掉了一幀,但是第二幀沒有收到任何影響。

總結

以上是生活随笔為你收集整理的renderthread是什么_Android5.0中 hwui 中 RenderThread 工作流程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美高清在线观看 | 午夜视频免费在线 | 呦呦色| 国产在线麻豆精品观看 | 视频一区二区在线 | 成人激情电影在线观看 | av综合网站 | 青青草中文字幕 | 日韩精选 | 最近高清中文在线字幕在线观看 | mm视频在线观看 | 在线a| 无码人妻久久一区二区三区蜜桃 | www四虎 | 色香蕉影院 | 欧美日韩在线免费视频 | 1级av| 国产人澡人澡澡澡人碰视频 | 欧美少妇xxx | 一本到在线| 日本a在线播放 | 国产在线精品一区二区三区 | 女仆裸体打屁屁羞羞免费 | 91精品国产高清91久久久久久 | 怒海潜沙秦岭神树 | 久久久久久久久久久久 | 色999在线观看 | 久久社区视频 | 少妇太紧太爽又黄又硬又爽 | 一本大道一区二区 | 国产69精品久久久久久久久久 | 激情四月| 香蕉人妻av久久久久天天 | 成人亚洲黄色 | 一区国产在线 | 亚洲一区二区三区免费看 | 永久视频 | 美攻壮受大胸奶汁(高h) | 欧美日韩国产精品一区 | 午夜性影院 | 久久午夜国产 | 国产精品高清无码 | 2022精品国偷自产免费观看 | 免费插插视频 | 中国美女乱淫免费看视频 | 国产精品videossex久久发布 | 亚洲男人的天堂在线 | 中国毛片网站 | 四虎永久免费影院 | 韩国一区二区视频 | 欧美1区 | 成人乱人乱一区二区三区 | 无码人妻精品一区二 | 日韩成人一区二区 | 久色91| 内谢少妇xxxxx8老少交视频 | 97av在线 | 国内av自拍 | 国产精华一区二区三区 | 黄色一级视频免费观看 | 亚洲不卡中文字幕无码 | 芒果视频在线观看免费 | 最新毛片基地 | 91精品国产日韩91久久久久久 | 69成人网 | 性欧美又大又长又硬 | 一级久久 | 亚洲av无一区二区三区怡春院 | 涩色视频 | 手机看片日韩 | 日本午夜网站 | 国产一级做a爱免费视频 | 九九黄色大片 | 国产区精品在线观看 | 亚洲精品tv | 精品人妻一区二区三区四区不卡 | 日韩亚洲一区二区 | 超碰pron| 美女av免费在线观看 | 91精品专区 | 亚洲一区二区三区电影在线观看 | 天天干狠狠干 | 人人妻人人澡人人爽欧美一区 | 国产性猛交96| 国产精品一区二区免费视频 | 在线播放不卡av | 日韩精品色呦呦 | 亚洲一区二区三区免费观看 | 久久久久免费看 | 海角社区在线视频播放观看 | 久久久噜噜噜久久中文字幕色伊伊 | 91亚洲精品国偷拍 | 亚洲国产精品成人va在线观看 | 久久青青热 | 午夜激情电影在线观看 | 超碰成人免费在线 | 亚洲在线观看av | 特级做a爰片毛片免费69 | 97在线视频免费观看 |