android Gui系统之SurfaceFlinger(5)
Joyfulmath 发布于2016-06-30 22:00
9.Vsync第二部分
在上一篇中我们讲到,视图的刷新需要很多步骤,
void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
preComposition(); //合成前的准备
rebuildLayerStacks();//重新建立layer堆栈
setUpHWComposer();//HWComposer的设定
#ifdef QCOM_BSP
setUpTiledDr();
#endif
doDebugFlashRegions();
doComposition(); //正式合成工作
postComposition(); //合成的后期工作
}
本文将继续分析这些过程。
9.1 handlerMessageInvalidate
invalidate 字面意思就是使无效,更进一步就是当前的buffer已经无限,请刷新界面。
啥也没干,buffer已经无效,我换下一个,就是handlePageFlip
void SurfaceFlinger::handleMessageInvalidate() {
ATRACE_CALL();
handlePageFlip();
}
再来看这个函数:handlePageFlip
handlePageFlip
@step1:layer->latchBuffer(visibleRegions) 通过该函数锁定各layer的缓冲区。可以理解这个函数一定与BufferQueue有关。
status_t updateResult = mSurfaceFlingerConsumer->updateTexImage(&r,
mFlinger->mPrimaryDispSync);
上面是latchBuffer的核心语句。SurfaceFlingerConsumer前文已经提过,是client端操作bufferqueue的一个端口。所以这个函数一定是操作bufferqueue的。
// Acquire the next buffer.
// In asynchronous mode the list is guaranteed to be one buffer
// deep, while in synchronous mode we use the oldest buffer.
err = acquireBufferLocked(&item, computeExpectedPresent(dispSync));
if (err != NO_ERROR) {
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
err = NO_ERROR;
} else if (err == BufferQueue::PRESENT_LATER) {
// return the error, without logging
} else {
ALOGE("updateTexImage: acquire failed: %s (%d)",
strerror(-err), err);
}
return err;
}
// We call the rejecter here, in case the caller has a reason to
// not accept this buffer. This is used by SurfaceFlinger to
// reject buffers which have the wrong size
int buf = item.mBuf;
if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
releaseBufferLocked(buf, mSlots[buf].mGraphicBuffer, EGL_NO_SYNC_KHR);
return NO_ERROR;
}
// Release the previous buffer.
err = updateAndReleaseLocked(item);
if (err != NO_ERROR) {
return err;
}
看了注释,基本解释了大体的过程。
1) 请求新的buffer
2)通过rejecter来判断申请的buffer是否满足surfaceflinger的要求。
3)释放之前的buffer
具体流程可以参考如下:
@step2:SurfaceFlinger:invalidateLayerStack来更新各个区域。
9.2 preComposition 合成前的准备
首先来看2个Vsync Rate相关的代码:
virtual void setVsyncRate(uint32_t count)
virtual void requestNextVsync()
当count为1时,表示每个信号都要报告,当count =2 时,表示信号 一个间隔一个报告,当count =0时,表示不自动报告,除非主动触发requestNextVsync
void SurfaceFlinger::preComposition()
{
bool needExtraInvalidate = false;
const LayerVector& layers(mDrawingState.layersSortedByZ);
const size_t count = layers.size();
for (size_t i=0 ; i
if (layers[i]->onPreComposition()) {
needExtraInvalidate = true;
}
}
if (needExtraInvalidate) {
signalLayerUpdate();
}
}
代码很简单,其实一共就3步,
1)获取全部的layer
2)每个layer onPrecomposition
3) layer update
bool Layer::onPreComposition() {
mRefreshPending = false;
return mQueuedFrames > 0 || mSidebandStreamChanged;
}
也就是说,当layer里存放被queue的frame以后,就会出发layer update.
void SurfaceFlinger::signalLayerUpdate() {
mEventQueue.invalidate();
}
最终会调用:
void EventThread::Connection::requestNextVsync() {
mEventThread->requestNextVsync(this);
}
void EventThread::requestNextVsync(
const sp& connection) {
Mutex::Autolock _l(mLock);
if (connection->count < 0) {
connection->count = 0;
mCondition.broadcast();//通知对vsync感兴趣的类
}
}
那么谁在等待这个broadcast呢?
还是EventThread
void EventThread::onVSyncEvent(nsecs_t timestamp) {
Mutex::Autolock _l(mLock);
mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
mVSyncEvent[0].header.id = 0;
mVSyncEvent[0].header.timestamp = timestamp;
mVSyncEvent[0].vsync.count++;
mCondition.broadcast();
}
9.3可见区域rebuildlayerStack
rebuildLayerStacks
前文提到mVisibleRegionsDirty这个变量是标记要刷新的可见区域的,我们按字面意思解释下:脏的可见区域,顾名思义,这就是要刷新的区域,因为buffer已经“脏”了。
@step1:系统的display可能不止一个,存在与mDisplays中。
@step2:computeVisibleRegions这个函数根据所有的layer状态,得到2个重要的变量。opaqueRegion & dirtyRegion
dirtyRegion是需要被刷新的。 opaqueRegion 不透明区域,应为layer是按Z-order排序的,左右排在前面的opaqueRegion 会挡住后面的layer。
@step3:Region drawRegion(tr.transform( layer->visibleNonTransparentRegion));程序需要进一步得出每个layer 绘制的区域。
系统的display(显示器)可能不止一个,但是所有的layer都记录在layersSortedByZ里面。记录每个layer属于那个display的变量是 hw->getLayerStack()
@step4:将结果保存到hw中。
这里的不透明区域 是很有意义的一个概念,就是我们在Z-order 上,越靠近用户的时候,值越大,所以是递减操作。
9.4 setUpHWComposer 搭建环境
用于合成surface的功能模块可以有2个,OpenGL ES & HWC,它的管理实在HWC里面实现的。
setUpHWComposer 总的来说就干了3件事情。
1)构造Worklist,并且给DisplayData:list 申请空间
2)填充各layer数据
3)报告HWC(有其他地方决定使用那个)
9.5 doCompostion
关键地方来了,上面的setUpHWComposer 只是交给HWC来负责显示,真正显示的地方就在这里。
1)如何合成
2)如何显示到屏幕上
合成的流程大体如上图。
有了概念后,分析源码:
void SurfaceFlinger::doComposition() {
ATRACE_CALL();
const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
for (size_t dpy=0 ; dpy
const sp& 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);
++mActiveFrameSequence;
hw->dirtyRegion.clear();
hw->flip(hw->swapRegion);
hw->swapRegion.clear();
}
// inform the h/w that we're done compositing
hw->compositionComplete();
}
postFramebuffer();
}
变量mRepaintEverything用于说明,是否需要全部重绘所有内容。如果为true的化,那么dirtyRegion就是displaydevice的 width & height构成的RECT。
否则由dirtyRegion转换而来。
doDisplayComposition是每个Display来处理,有可能会用到OpenGL 的接口来交换buffer。
hw->compositionComplete(); 通知HWC合成结束了。
postFramebuffer HWC的Set接口调用。
9.5.1 doDisplayComposition
doDisplayComposition
传入的参数inDirtyRegion,这就是要刷新的“脏”区域,but,我们的刷新机制,决定了必须是矩形的区域。
So,需要一个最小的矩形,能够包裹inDirtyRegion的区域。
SWAP_RECTANGLE:系统支持软件层面的部分刷新,就需要计算这个最小矩形。
PARTIAL_UPDATES:硬件层面的部分刷新,同理需要这个最小矩形。
最后就是重绘这个区域。
doComposeSurfaces
依次分析:hasGlesComposition需要Open GL来合成的layer,hasHwcComposition需要HWC来合成的layer。
这2各变量不是互斥的,有同时存在需要Open GL layer & HWC layer。
hasHwcComposition在2种情况下是true。
1)layer的类型是HWC_Framebuffer的时候,通常情况下是true。
2)cur ==end 核心实现layer->draw 来完成。
3)cur!=end, 将有hwc来实现。
{
ATRACE_CALL();
if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
// SurfaceView because the WindowManager can't know when the client
// has drawn the first time.
// If there is nothing under us, we paint the screen in black, otherwise
// we just skip this update.
// figure out if there is something below us
Region under;
const SurfaceFlinger::LayerVector& drawingLayers(
mFlinger->mDrawingState.layersSortedByZ);
const size_t count = drawingLayers.size();
for (size_t i=0 ; i
const sp& layer(drawingLayers[i]);
if (layer.get() == static_cast(this))
break;
under.orSelf( hw->getTransform().transform(layer->visibleRegion) );
}
// if not everything below us is covered, we plug the holes!
Region holes(clip.subtract(under));
if (!holes.isEmpty()) {
clearWithOpenGL(hw, holes, 0, 0, 0, 1);
}
return;
}
// Bind the current buffer to the GL texture, and wait for it to be
// ready for us to draw into.
status_t err = mSurfaceFlingerConsumer->bindTextureImage();
if (err != NO_ERROR) {
ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
// Go ahead and draw the buffer anyway; no matter what we do the screen
// is probably going to have something visibly wrong.
}
bool blackOutLayer = isProtected() || (isSecure() && !hw->isSecure());
RenderEngine& engine(mFlinger->getRenderEngine());
if (!blackOutLayer) {
// TODO: we could be more subtle with isFixedSize()
const bool useFiltering = getFiltering() || needsFiltering(hw) || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
if (mSurfaceFlingerConsumer->getTransformToDisplayInverse()) {
/*
* the code below applies the display's inverse transform to the texture transform
*/
// create a 4x4 transform matrix from the display transform flags
const mat4 flipH(-1,0,0,0, 0,1,0,0, 0,0,1,0, 1,0,0,1);
const mat4 flipV( 1,0,0,0, 0,-1,0,0, 0,0,1,0, 0,1,0,1);
const mat4 rot90( 0,1,0,0, -1,0,0,0, 0,0,1,0, 1,0,0,1);
mat4 tr;
uint32_t transform = hw->getOrientationTransform();
if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90)
tr = tr * rot90;
if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H)
tr = tr * flipH;
if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V)
tr = tr * flipV;
// calculate the inverse
tr = inverse(tr);
// and finally apply it to the original texture matrix
const mat4 texTransform(mat4(static_cast(textureMatrix)) * tr);
memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
}
// Set things up for texturing.
mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
mTexture.setFiltering(useFiltering);
mTexture.setMatrix(textureMatrix);
engine.setupLayerTexturing(mTexture);
} else {
engine.setupLayerBlackedOut();
}
drawWithOpenGL(hw, clip, useIdentityTransform);
engine.disableTexturing();
}
里面关键就是drawwithOpenGL,可见是由Open GL来合成layer。
查看原文