硬件加速涉及到绘制的核心类
上一篇,比较仓促的就开始说硬件加速的代码了,没有理一下核心类,在这里补一下,首先最核心的入口就是RenderProxy, Proxy的创建在ThreadRender 的 继承类 HandwareRender构造方法里 nCreateProxy()里,创建RenderProxy.
RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
IContextFactory* contextFactory)
: mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
});
mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
}
可以看到代码初始化时,同时创建了:
1, RenderThread(也就是硬件加速的渲染线程,所有硬件渲染,都会在这个线程的Looper中执行).
2,CanvasContext(所有渲染的上下文,将持有各种渲染的PipleLine,一共找到三个pipeline, SkiaPipeLine, 以及继承自SkiaPipeLine的 (SkiaOpenGlPipeLine, SkiaVulkanPipeLine).
3,DrawFrameTask,绘制某一帧的任务.
CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
RenderNode* rootRenderNode, IContextFactory* contextFactory) {
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
case RenderPipelineType::SkiaGL:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
case RenderPipelineType::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;
CanvasContext初始化时,会根据properties的配置选择使用SkiaOpenGl或者SkiaVulkan的一种. 接下来继续看核心类RenderThread: 调用start后的核心代码.
bool RenderThread::threadLoop() {
//设置优先级,THREAD_PRIORITY_DISPLAY, 是标准显示优先级.标准显示系统优先级,主要是改善UI的刷新.
setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
Looper::setForThread(mLooper);
if (gOnStartHook) {
gOnStartHook("RenderThread");
}
//初始化 当前线程的变量
initThreadLocals();
while (true) {
//循环,阻塞,等待消息进入队列时唤醒,应该类似java层MessageQueue的 nativePollOnce()
//最终调用的也是Loop.poolOnce()
waitForWork();
//处理workQueue里的任务.
processQueue();
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
drainDisplayEventQueue();
mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
requestVsync();
}
if (!mFrameCallbackTaskPending && !mVsyncRequested && mFrameCallbacks.size()) {
// TODO: Clean this up. This is working around an issue where a combination
// of bad timing and slow drawing can result in dropping a stale vsync
// on the floor (correct!) but fails to schedule to listen for the
// next vsync (oops), so none of the callbacks are run.
requestVsync();
`}`
}
return false;
}
先看一下initThreslocals
void RenderThread::initThreadLocals() {
setupFrameInterval();
//初始化监听Vsync信号
initializeDisplayEventReceiver();
mEglManager = new EglManager();
mRenderState = new RenderState(*this);
mVkManager = new VulkanManager();
mCacheManager = new CacheManager(DeviceInfo::get()->displayInfo());
}
EglManager:当使用openGl等相关管道时,会通过这个类进行OpenGl上下文的操作.
VulkanManager: 当使用Vulkan等相关管道时,会通过这个类进行Vulkan上下文操作.
RenderState: 渲染状态,持有了renderThread对象,而renderThread又持有了eglManager和vulkanManager
CacheManager:更像是一个内存缓存管理.里面定义了onTrimMemory等方法.
`
void RenderThread::initializeDisplayEventReceiver() {
LOG_ALWAYS_FATAL_IF(mVsyncSource, "Initializing a second DisplayEventReceiver?");
if (!Properties::isolatedProcess) {
auto receiver = std::make_unique<DisplayEventReceiver>(
ISurfaceComposer::eVsyncSourceApp,
ISurfaceComposer::eConfigChangedDispatch);
status_t status = receiver->initCheck();
LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
"Initialization of DisplayEventReceiver "
"failed with status: %d",
status);
// Register the FD
// looper在这注册了DisplayEventReceiver的监听
mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
RenderThread::displayEventReceiverCallback, this);
mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver), [this] {
DeviceInfo::get()->onDisplayConfigChanged();
setupFrameInterval();
});
} else {
mVsyncSource = new DummyVsyncSource(this);
}
}
这个方法初始化了DisplayEventReceiver ,这个能收到vSync的回调, 同时looper注册了receiver的回调,回调方法是displayEventReceiverCallBack()
displayEventReceiverCallBack,最后又调用了drainDisplayEventQueue(),这个向workQueue添加了一个任务dispatchFrameCallbacks(). 这个IFrameCallback最终会调用CanvasContext中的 doFrame(),prepareTree()
追踪一下,这个代码是ViewRootImpl在scheduleTraversals()中调用的notifyRendererOfFramePending()中添加的.添加目的是什么呢?
/**
* Notifies the hardware renderer that a call to {@link FrameRenderRequest#syncAndDraw()} will
* be coming soon. This is used to help schedule when RenderThread-driven animations will
* happen as the renderer wants to avoid producing more than one frame per vsync signal.
*/
public void notifyFramePending() {
nNotifyFramePending(mNativeProxy);
}
我们看一下HardwareRender中的notifyFramePending,也就是添加IFrameCallBack的java层调用方法. 意思是通知handware render,一个 syncAndDraw()任务马上就要到了(Choregrapher收到vsync后开始执行的?) 这些有助于安排 render 何时执行 RenderThread-driven 动画,从而避免 每个Vsync周期内,产生超过一帧数据.
硬件加速开始绘制
上文,我们简单提到了硬件加速开始绘制的方法,所以,现在我们直接从DrawFrameTask的run方法向下看
void DrawFrameTask::run() {
ATRACE_NAME("DrawFrame");
bool canUnblockUiThread;
bool canDrawThisFrame;
{
TreeInfo info(TreeInfo::MODE_FULL, *mContext);
canUnblockUiThread = syncFrameState(info);
canDrawThisFrame = info.out.canDrawThisFrame;
//为CanvasContext添加一个绘制完成的回调,mFrameCompleteCallBack
if (mFrameCompleteCallback) {
mContext->addFrameCompleteListener(std::move(mFrameCompleteCallback));
mFrameCompleteCallback = nullptr;
}
}
// Grab a copy of everything we need
CanvasContext* context = mContext;
std::function<void(int64_t)> callback = std::move(mFrameCallback);
mFrameCallback = nullptr;
// From this point on anything in "this" is *UNSAFE TO ACCESS*
if (canUnblockUiThread) {
unblockUiThread();
}
// Even if we aren't drawing this vsync pulse the next frame number will still be accurate
if (CC_UNLIKELY(callback)) {
context->enqueueFrameWork(
[callback, frameNr = context->getFrameNumber()]() { callback(frameNr); });
}
if (CC_LIKELY(canDrawThisFrame)) {
context->draw();
} else {
// wait on fences so tasks don't overlap next frame
context->waitOnFences();
}
if (!canUnblockUiThread) {
unblockUiThread();
}
}
比较重要的方法,有两个:
1, syncFrameState() 这个方法里又会调用CanvasContext中的prepareTree(),用来准备渲染树.
2, CanvasContext.draw()绘制流程
准备渲染树
先看一下 syncFrameState()方法:
bool DrawFrameTask::syncFrameState(TreeInfo& info) {
ATRACE_CALL();
int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
mRenderThread->timeLord().vsyncReceived(vsync);
//1, 创建OpenGl或者Vulkan的上下文
bool canDraw = mContext->makeCurrent();
//2, 最终调用OpenGl或者Vulkan中的 unpinImages()方法,获取所有纹理并重置.
mContext->unpinImages();
//3, 处理保存在mDisplayList中的Layer逻辑
for (size_t i = 0; i < mLayers.size(); i++) {
mLayers[i]->apply();
}
mLayers.clear();
mContext->setContentDrawBounds(mContentDrawBounds);
//4, 调用prepareTree,准备渲染树.
mContext->prepareTree(info, mFrameInfo, mSyncQueued, mTargetNode);
// This is after the prepareTree so that any pending operations
// (RenderNode tree state, prefetched layers, etc...) will be flushed.
if (CC_UNLIKELY(!mContext->hasSurface() || !canDraw)) {
if (!mContext->hasSurface()) {
mSyncResult |= SyncResult::LostSurfaceRewardIfFound;
} else {
// If we have a surface but can't draw we must be stopped
mSyncResult |= SyncResult::ContextIsStopped;
}
info.out.canDrawThisFrame = false;
}
if (info.out.hasAnimations) {
if (info.out.requiresUiRedraw) {
mSyncResult |= SyncResult::UIRedrawRequired;
}
}
if (!info.out.canDrawThisFrame) {
mSyncResult |= SyncResult::FrameDropped;
}
// If prepareTextures is false, we ran out of texture cache space
return info.prepareTextures;
}
来看prepareTree逻辑.
void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
RenderNode* target) {
mRenderThread.removeFrameCallback(this);
// If the previous frame was dropped we don't need to hold onto it, so
// just keep using the previous frame's structure instead
if (!wasSkipped(mCurrentFrameInfo)) {
mCurrentFrameInfo = mJankTracker.startFrame();
}
mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
mCurrentFrameInfo->set(FrameInfoIndex::SyncQueued) = syncQueued;
mCurrentFrameInfo->markSyncStart();
info.damageAccumulator = &mDamageAccumulator;
info.layerUpdateQueue = &mLayerUpdateQueue;
info.out.canDrawThisFrame = true;
mAnimationContext->startFrame(info.mode);
mRenderPipeline->onPrepareTree();
for (const sp<RenderNode>& node : mRenderNodes) {
// Only the primary target node will be drawn full - all other nodes would get drawn in
// real time mode. In case of a window, the primary node is the window content and the other
// node(s) are non client / filler nodes.
info.mode = (node.get() == target ? TreeInfo::MODE_FULL : TreeInfo::MODE_RT_ONLY);
node->prepareTree(info);
GL_CHECKPOINT(MODERATE);
}
mAnimationContext->runRemainingAnimations(info);
GL_CHECKPOINT(MODERATE);
freePrefetchedLayers();
GL_CHECKPOINT(MODERATE);
mIsDirty = true;
if (CC_UNLIKELY(!hasSurface())) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
info.out.canDrawThisFrame = false;
return;
}
if (CC_LIKELY(mSwapHistory.size() && !Properties::forceDrawFrame)) {
nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
SwapHistory& lastSwap = mSwapHistory.back();
nsecs_t vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
// The slight fudge-factor is to deal with cases where
// the vsync was estimated due to being slow handling the signal.
// See the logic in TimeLord#computeFrameTimeNanos or in
// Choreographer.java for details on when this happens
if (vsyncDelta < 2_ms) {
// Already drew for this vsync pulse, UI draw request missed
// the deadline for RT animations
info.out.canDrawThisFrame = false;
}
} else {
info.out.canDrawThisFrame = true;
}
// TODO: Do we need to abort out if the backdrop is added but not ready? Should that even
// be an allowable combination?
if (mRenderNodes.size() > 2 && !mRenderNodes[1]->isRenderable()) {
info.out.canDrawThisFrame = false;
}
if (info.out.canDrawThisFrame) {
int err = mNativeSurface->reserveNext();
if (err != OK) {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
info.out.canDrawThisFrame = false;
ALOGW("reserveNext failed, error = %d (%s)", err, strerror(-err));
if (err != TIMED_OUT) {
// A timed out surface can still recover, but assume others are permanently dead.
setSurface(nullptr);
return;
}
}
} else {
mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
}
bool postedFrameCallback = false;
if (info.out.hasAnimations || !info.out.canDrawThisFrame) {
if (CC_UNLIKELY(!Properties::enableRTAnimations)) {
info.out.requiresUiRedraw = true;
}
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);
postedFrameCallback = true;
}
}
if (!postedFrameCallback &&
info.out.animatedImageDelay != TreeInfo::Out::kNoAnimatedImageDelay) {
// Subtract the time of one frame so it can be displayed on time.
const nsecs_t kFrameTime = mRenderThread.timeLord().frameIntervalNanos();
if (info.out.animatedImageDelay <= kFrameTime) {
mRenderThread.postFrameCallback(this);
} else {
const auto delay = info.out.animatedImageDelay - kFrameTime;
int genId = mGenerationID;
mRenderThread.queue().postDelayed(delay, [this, genId]() {
if (mGenerationID == genId) {
mRenderThread.postFrameCallback(this);
}
});
}
}
}
一般情况下,mRenderNodes里面应该只有一个RenderNode
加下来,会执行RenderNode.prepareTree()