前面的文章介绍了HardwareRendere在初始化的时分,触及到了一个组件RenderThread并简要的剖析了一下,这篇文章将持续深化的剖析一下这个RenderThread,介绍一下它的几个重要特性和功用
1 Thread
RenderThread首先是承继自ThreadBase,是一个实在的线程。
frameworks/base/libs/hwui/renderthread/RenderThread.h
class RenderThread : private ThreadBase {
PREVENT_COPY_AND_ASSIGN(RenderThread);
frameworks/base/libs/hwui/thread/ThreadBase.h
ThreadBase()
: Thread(false)
, mLooper(new Looper(false))
, mQueue([this]() { mLooper->wake(); }, mLock) {}
ThreadBase是一个hwui中界说的一个线程类,它由一个音讯循环Looper,作业行列mQueue,和一个锁mLock组成,承继自util/Thread,经过系统调用pthread_create创建的线程,它的进口是一个无限循环函数_threadLoop.。
system/core/libutils/Threads.cpp
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
int Thread::_threadLoop(void* user) {
Thread* const self = static_cast<Thread*>(user);
sp<Thread> strong(self->mHoldSelf);
...
do {
bool result;
result = self->threadLoop();
}
...
} while(strong != nullptr);
return 0;
}
每次循环都去履行threadLoop办法。在hwui的ThreadBase里面完成了这办法。
frameworks/base/libs/hwui/thread/ThreadBase.h
virtual bool threadLoop() override {
Looper::setForThread(mLooper);
while (!exitPending()) {
waitForWork();
processQueue();
}
Looper::setForThread(nullptr);
return false;
}
在第一次调用threadLoop的时分,会进入到ThreadBase自身的一个无限循环中,所以threadLoop只会履行一次。 在这一次履行中,会给当时的线程绑定一个Looper。在ThreadBase中会去调用waitForWork比及looper中的音讯,收到音讯线程被唤醒后,履行processQueue。处理使命行列中的使命。
void waitForWork() {
nsecs_t nextWakeup;
{
std::unique_lock lock{mLock};
nextWakeup = mQueue.nextWakeup(lock);
}
int timeout = -1;
if (nextWakeup < std::numeric_limits<nsecs_t>::max()) {
timeout = ns2ms(nextWakeup - WorkQueue::clock::now());
if (timeout < 0) timeout = 0;
}
int result = mLooper->pollOnce(timeout);
LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, "RenderThread Looper POLL_ERROR!");
}
这儿会一向阻塞到mLooper->pollOnce返回。之后就履行processQueue处理使命行列mQueue. 使命行列的类型是WorkQueue
void processQueue() { mQueue.process(); }
frameworks/base/libs/hwui/thread/WorkQueue.h
void process() {
auto now = clock::now();
std::vector<WorkItem> toProcess;
{
std::unique_lock _lock{mLock};
if (mWorkQueue.empty()) return;
toProcess = std::move(mWorkQueue);
auto moveBack = find_if(std::begin(toProcess), std::end(toProcess),
[&now](WorkItem& item) { return item.runAt > now; });
if (moveBack != std::end(toProcess)) {
mWorkQueue.reserve(std::distance(moveBack, std::end(toProcess)) + 5);
std::move(moveBack, std::end(toProcess), std::back_inserter(mWorkQueue));
toProcess.erase(moveBack, std::end(toProcess));
}
}
for (auto& item : toProcess) {
item.work();
}
}
这个行列筛选出一切可以处理的WorkItem(runAt < now),然后再循环处理它们。当有使命需求交给这个线程履行的时分,可以获取到这个mQueue,然后调用添加使命的办法,比如post办法
template <class F>
void postAt(nsecs_t time, F&& func) {
enqueue(WorkItem{time, std::function<void()>(std::forward<F>(func))});
}
然后调用到入队的enqueue办法
void enqueue(WorkItem&& item) {
bool needsWakeup;
{
std::unique_lock _lock{mLock};
auto insertAt = std::find_if(
std::begin(mWorkQueue), std::end(mWorkQueue),
[time = item.runAt](WorkItem & item) { return item.runAt > time; });
needsWakeup = std::begin(mWorkQueue) == insertAt;
mWorkQueue.emplace(insertAt, std::move(item));
}
if (needsWakeup) {
mWakeFunc();
}
}
假如新的这使命放到行列的头部的话,就调用mWakeFunc办法,这个办法是结构Queue的时分传入的,回看上面ThreadBase的结构办法,传入的是 this { mLooper->wake()},因而会唤醒mLooper的pollOnce,然后线程开端处理作业行列,整个RenderThread线程的履行流程就理顺了,跟java层的HandlerThread很相似。
2 threadLoop
RenderThread 重写了threadLoop办法,所以履行的是它自己的threadLoop办法
bool RenderThread::threadLoop() {
...
initThreadLocals();
while (true) {
waitForWork();
processQueue();
...
if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
requestVsync();
}
}
return false;
}
主要的流程和父类的threadLoop差不多,只是这儿多了几个处理,一个是初始化,另外一个是处理完作业行列后,在一定条件下调用requestVsync,也便是说再处理完一个制作使命后,再RenderThread里也可能会请求vsync信号,来看一下RenderThread的Vsync机制。
void RenderThread::initThreadLocals() {
setupFrameInterval();
initializeChoreographer();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
mVkManager = VulkanManager::getInstance();
mCacheManager = new CacheManager();
}
void RenderThread::setupFrameInterval() {
nsecs_t frameIntervalNanos = DeviceInfo::getVsyncPeriod();
mTimeLord.setFrameInterval(frameIntervalNanos);
mDispatchFrameDelay = static_cast<nsecs_t>(frameIntervalNanos * .25f);
}
setupFrameInterval比较简单,它读取的 DeviceInfo::getVsyncPeriod(),这个是在Java层初始化HardwareRenderer的时分设置到C层。接着调用initializeChoreographer初始话C层的Choreographer. 那这儿便是关于Vsync的逻辑了。
void RenderThread::initializeChoreographer() {
...
mChoreographer = AChoreographer_create();
LOG_ALWAYS_FATAL_IF(mChoreographer == nullptr, "Initialization of Choreographer failed");
AChoreographer_registerRefreshRateCallback(mChoreographer,
RenderThread::refreshRateCallback, this);
// Register the FD
mLooper->addFd(AChoreographer_getFd(mChoreographer), 0, Looper::EVENT_INPUT,
RenderThread::choreographerCallback, this);
mVsyncSource = new ChoreographerSource(this);
}
经过AChoreographer_create办法,创建一个C层的Choreographer目标,并调用AChoreographer_registerRefreshRateCallback注册刷新率更新的回调,当屏幕刷新率改变之后调用setupFrameInterval办法。然后让当时RenderThread的looper去观察mChoreographer文件描述符,假如由输入事件,则调用choreographerCallback办法。最终生成一个ChoreographerSource目标。C层的AChoreographer处理VSync的流程咱们先不看,咱们来看看什么RenderThread需求监听Vsync。 在threadLoop中,当履行完一次使命后(processQueue),会判别是否需求requestVsync。它的条件是
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
mVsyncSource->drainPendingEvents();
mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
requestVsync();
}
也便是当mPendingRegistrationFrameCallbacks不为空的时分且还没有履行回调的,会去requestVsync。 这是因为processQueue仅仅只完成了CPU的作业,GPU和HWComposer是否完成显现是不知道的,而mPendingRegistrationFrameCallbacks是延迟制作使命,它通常是由动画导致的,需求比及一帧显现完毕才干回调,因而这儿就需求去监听Vsync,收到Vsync之后才去回调callback。RenderThread提供注册的办法:
void RenderThread::postFrameCallback(IFrameCallback* callback) {
mPendingRegistrationFrameCallbacks.insert(callback);
}
因而假如没有mPendingRegistrationFrameCallbacks的话,EventThread就不需求请求Vsync了
3 requireGlContext
这个办法是准备GPU制作的上下文,需求在制作之前准备好向GPU提交数据的相关才能
void RenderThread::requireGlContext() {
if (mEglManager->hasEglContext()) {
return;
}
mEglManager->initialize();
sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
LOG_ALWAYS_FATAL_IF(!glInterface.get());
GrContextOptions options;
initGrContextOptions(options);
auto glesVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
auto size = glesVersion ? strlen(glesVersion) : -1;
cacheManager().configureContext(&options, glesVersion, size);
sk_sp<GrDirectContext> grContext(GrDirectContext::MakeGL(std::move(glInterface), options));
LOG_ALWAYS_FATAL_IF(!grContext.get());
setGrContext(grContext);
}
- mEglManager->initialize();加载EGL驱动,初始化EGL
- glInterface(GrGLCreateNativeInterface()),GrGLCreateNativeInterface()里封装一切的openGL接口_external/skia/src/gpu/gl/egl/GrGLMakeEGLInterface.cpp_
sk_sp<const GrGLInterface> GrGLMakeEGLInterface() {
return GrGLMakeAssembledInterface(nullptr, egl_get_gl_proc);
}
static GrGLFuncPtr egl_get_gl_proc(void* ctx, const char name[]) {
...
#define M(X) if (0 == strcmp(#X, name)) { return (GrGLFuncPtr) X; }
M(eglGetCurrentDisplay)
M(eglQueryString)
....
#undef M
return eglGetProcAddress(name);
}
- grContext(GrDirectContext::MakeGL(std::move(glInterface), options)); 创建GPU制作的上下文GrDirectContext,并初始化它的成员fGpu,它将担任向GPU提交数据。
sk_sp<GrDirectContext> GrDirectContext::MakeGL(sk_sp<const GrGLInterface> glInterface,
const GrContextOptions& options) {
sk_sp<GrDirectContext> direct(new GrDirectContext(GrBackendApi::kOpenGL, options));
...
direct->fGpu = GrGLGpu::Make(std::move(glInterface), options, direct.get());
if (!direct->init()) {
return nullptr;
}
return direct;
}
到这儿EventThread里就具备了请求GPU进行OpenGL烘托的才能了。
4 总结
本文主要介绍了EventThread这个组件相关的功用,主要包含了以下内容
- 线程和使命行列原理
- vsync机制
- 初始化EGLManager,GrDirectContext,并创建好了向GPU提交数据的GrGLGpu目标。
关注大众号:Android老皮!!!欢迎大家来找我探讨交流