Android P 显示流程分析---界面刷新
Posted Give.Me.Five
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android P 显示流程分析---界面刷新相关的知识,希望对你有一定的参考价值。
上篇分析完了setUpHWComposer(), 这篇就来分析实际图层合成部分了。
void SurfaceFlinger::doComposition()
const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
//遍历所有显示屏
for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++)
const sp<DisplayDevice>& hw(mDisplays[dpy]);
if (hw->isDisplayOn())
//找到所有发生了变化的区域,即脏区域
// transform the dirty region into this screen's coordinate space
const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
//重画所有的脏区域
// repaint the framebuffer (if needed)
doDisplayComposition(hw, dirtyRegion);
hw->dirtyRegion.clear();
hw->flip();
//发送Framebuffer
postFramebuffer();
dirtyRegion(hw->getDirtyRegion(repaintEverything))
找到发生变化的区域
Region DisplayDevice::getDirtyRegion(bool repaintEverything) const
Region dirty;
//这里的repainEverything = 0
if (repaintEverything)
dirty.set(getBounds());
else
const Transform& planeTransform(mGlobalTransform);
dirty = planeTransform.transform(this->dirtyRegion);
dirty.andSelf(getBounds());
return dirty;
//确实显示区域的上下左右
FloatRect Transform::transform(const FloatRect& bounds) const
vec2 lt(bounds.left, bounds.top);
vec2 rt(bounds.right, bounds.top);
vec2 lb(bounds.left, bounds.bottom);
vec2 rb(bounds.right, bounds.bottom);
lt = transform(lt);
rt = transform(rt);
lb = transform(lb);
rb = transform(rb);
FloatRect r;
r.left = min(lt[0], rt[0], lb[0], rb[0]);
r.top = min(lt[1], rt[1], lb[1], rb[1]);
r.right = max(lt[0], rt[0], lb[0], rb[0]);
r.bottom = max(lt[1], rt[1], lb[1], rb[1]);
return r;
doDisplayComposition(hw, dirtyRegion)
上面获取到了显示区域,现在需要做显示合成了
void SurfaceFlinger::doDisplayComposition(
const sp<const DisplayDevice>& displayDevice,
const Region& inDirtyRegion)
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
// 2) There is work to be done (the dirty region isn't empty)
bool isHwcDisplay = displayDevice->getHwcDisplayId() >= 0;
if (!isHwcDisplay && inDirtyRegion.isEmpty())
ALOGV("Skipping display composition");
return;
ALOGV("doDisplayComposition");
//设置渲染的区域,对区域做渲染的初始化,如颜色,区域大小等
if (!doComposeSurfaces(displayDevice)) return;
//交互分区
// swap buffers (presentation)
displayDevice->swapBuffers(getHwComposer());
这个里面做了两件事,一个是区域的初始化,主要是针对Render的。第二个是交互分区,这个需要重点分析下,分区是如何切换的
void DisplayDevice::swapBuffers(HWComposer& hwc) const
if (hwc.hasClientComposition(mHwcDisplayId) || hwc.hasFlipClientTargetRequest(mHwcDisplayId))
//surface 切换buffer
mSurface->swapBuffers();
//为下一个buffer做准备
status_t result = mDisplaySurface->advanceFrame();
if (result != NO_ERROR)
ALOGE("[%s] failed pushing new frame to HWC: %d",
mDisplayName.string(), result);
mSurface->swapBuffers() 也就是调用opengl里的最终送显函数eglSwapBuffers(mEGLDisplay, mEGLSurface)。
重点来看看如何为下一个buffer做准备的
status_t FramebufferSurface::advanceFrame()
uint32_t slot = 0;
sp<GraphicBuffer> buf;
sp<Fence> acquireFence(Fence::NO_FENCE);
Dataspace dataspace = Dataspace::UNKNOWN;
//获取下一个槽位,buffer,fence,以及数据空间
status_t result = nextBuffer(slot, buf, acquireFence, dataspace);
mDataSpace = dataspace;
if (result != NO_ERROR)
ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
strerror(-result), result);
return result;
继续分析nextBuffer
status_t FramebufferSurface::nextBuffer(uint32_t& outSlot,
sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence,
Dataspace& outDataspace)
Mutex::Autolock lock(mMutex);
BufferItem item;
//获取下一个Buffer
status_t err = acquireBufferLocked(&item, 0);
if (err == BufferQueue::NO_BUFFER_AVAILABLE)
//如果没有可用buff,从缓存中获取
mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
return NO_ERROR;
else if (err != NO_ERROR)
ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
return err;
// If the BufferQueue has freed and reallocated a buffer in mCurrentSlot
// then we may have acquired the slot we already own. If we had released
// our current buffer before we call acquireBuffer then that release call
// would have returned STALE_BUFFER_SLOT, and we would have called
// freeBufferLocked on that slot. Because the buffer slot has already
// been overwritten with the new buffer all we have to do is skip the
// releaseBuffer call and we should be in the same state we'd be in if we
// had released the old buffer first.
if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT &&
item.mSlot != mCurrentBufferSlot)
mHasPendingRelease = true;
mPreviousBufferSlot = mCurrentBufferSlot;
mPreviousBuffer = mCurrentBuffer;
mCurrentBufferSlot = item.mSlot;
mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
mCurrentFence = item.mFence;
outFence = item.mFence;
mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer,
&outSlot, &outBuffer);
outDataspace = static_cast<Dataspace>(item.mDataSpace);
//设置目标的显示buffer
status_t result =
mHwc.setClientTarget(mDisplayType, outSlot, outFence, outBuffer, outDataspace);
if (result != NO_ERROR)
ALOGE("error posting framebuffer: %d", result);
return result;
return NO_ERROR;
这里主要做了三件事,获取下一次显示的buffer, 将此buffer 做一个缓存处理,将buffer相关信息送到hwc中,设置为下一次目标。
往下看看获取buffer的过程:
status_t ConsumerBase::acquireBufferLocked(BufferItem *item,
nsecs_t presentWhen, uint64_t maxFrameNumber)
if (mAbandoned)
CB_LOGE("acquireBufferLocked: ConsumerBase is abandoned!");
return NO_INIT;
//从消费者获取可以用buffer
status_t err = mConsumer->acquireBuffer(item, presentWhen, maxFrameNumber);
if (err != NO_ERROR)
return err;
if (item->mGraphicBuffer != NULL)
if (mSlots[item->mSlot].mGraphicBuffer != NULL)
freeBufferLocked(item->mSlot);
mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
mSlots[item->mSlot].mFrameNumber = item->mFrameNumber;
mSlots[item->mSlot].mFence = item->mFence;
CB_LOGV("acquireBufferLocked: -> slot=%d/%" PRIu64,
item->mSlot, item->mFrameNumber);
return OK;
这里是从消费者的buffer队列中获取 到buffer, 这里要引出一个生产者–消费者模式的buffer队列。下一篇来重点讲生产者–消费者模式的Buffer对列。
postFramebuffer()
void SurfaceFlinger::postFramebuffer()
ATRACE_CALL();
ALOGV("postFramebuffer");
const nsecs_t now = systemTime();
mDebugInSwapBuffers = now;
//遍历所有显示屏
for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId)
auto& displayDevice = mDisplays[displayId];
if (!displayDevice->isDisplayOn())
continue;
const auto hwcId = displayDevice->getHwcDisplayId();
if (hwcId >= 0)
getBE().mHwc->presentAndGetReleaseFences(hwcId);
//回调onSwapBuffersCompleted()
displayDevice->onSwapBuffersCompleted();
//重新设置当前的Surface
displayDevice->makeCurrent();
//按照Z轴显示顺序来遍历图层
for (auto& layer : displayDevice->getVisibleLayersSortedByZ())
// The layer buffer from the previous frame (if any) is released
// by HWC only when the release fence from this frame (if any) is
// signaled. Always get the release fence from HWC first.
auto hwcLayer = layer->getHwcLayer(hwcId);
sp<Fence> releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
// If the layer was client composited in the previous frame, we
// need to merge with the previous client target acquire fence.
// Since we do not track that, always merge with the current
// client target acquire fence when it is available, even though
// this is suboptimal.
if (layer->getCompositionType(hwcId) == HWC2::Composition::Client)
releaseFence = Fence::merge("LayerRelease", releaseFence,
displayDevice->getClientTargetAcquireFence());
//根据释放的Fence来回调onLayerDisplayed
layer->onLayerDisplayed(releaseFence);
// We've got a list of layers needing fences, that are disjoint with
// displayDevice->getVisibleLayersSortedByZ. The best we can do is to
// supply them with the present fence.
if (!displayDevice->getLayersNeedingFences().isEmpty())
sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
for (auto& layer : displayDevice->getLayersNeedingFences())
//提供当前Fence给当前需要Fence的图层
layer->onLayerDisplayed(presentFence);
if (hwcId >= 0)
getBE().mHwc->clearReleaseFences(hwcId);
mLastSwapBufferTime = systemTime() - now;
mDebugInSwapBuffers = 0;
// |mStateLock| not needed as we are on the main thread
if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY))
uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0)
logFrameStats();
以上是关于Android P 显示流程分析---界面刷新的主要内容,如果未能解决你的问题,请参考以下文章
Android P 显示流程分析---EventThread MessageQueue 交互分析
Android P 显示流程---Display设备初始化过程分析
Android P 显示流程分析--- buffer的生产消费者模式