8.Vsync

8.1概论

VSYNC(Vertical Synchronization)是一个相当古老的概念,对于游戏玩家,它有一个更加大名鼎鼎的中文名字—-垂直同步。

“垂直同步(vsync)”指的是显卡的输出帧数和屏幕的垂直刷新率相同,这完全是一个CRT显示器上的概念。其实无论是VSYNC还是垂直同步这个名字,

因为LCD根本就没有垂直扫描的这种东西,因此这个名字本身已经没有意义。但是基于历史的原因,这个名称在图形图像领域被沿袭下来。
在当下,垂直同步的含义我们可以理解为,使得显卡生成帧的速度和屏幕刷新的速度的保持一致。举例来说,如果屏幕的刷新率为60Hz,那么生成帧

的速度就应该被固定在1/60 s。

8.2 VSync信号的产生和分发

VSync信号的产生在android_frameworks_native\services\surfaceflinger\DisplayHardware\HWComposer.cpp里面定义:

HWComposer::HWComposer(
const sp<SurfaceFlinger>& flinger,
EventHandler& handler)
: mFlinger(flinger),
mFbDev(), mHwc(), mNumDisplays(),
mCBContext(new cb_context),
mEventHandler(handler),
mDebugForceFakeVSync(false),
mVDSEnabled(false)
{
for (size_t i = ; i<MAX_HWC_DISPLAYS ; i++) {
mLists[i] = ;
} for (size_t i= ; i<HWC_NUM_PHYSICAL_DISPLAY_TYPES ; i++) {
mLastHwVSync[i] = ;
mVSyncCounts[i] = ;
} char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.no_hw_vsync", value, "");
mDebugForceFakeVSync = atoi(value); bool needVSyncThread = true; // Note: some devices may insist that the FB HAL be opened before HWC.
int fberr = loadFbHalModule();
loadHwcModule(); if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// close FB HAL if we don't needed it.
// FIXME: this is temporary until we're not forced to open FB HAL
// before HWC.
framebuffer_close(mFbDev);
mFbDev = NULL;
} // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
&& !mFbDev) {
ALOGE("ERROR: failed to open framebuffer (%s), aborting",
strerror(-fberr));
abort();
} // these display IDs are always reserved
for (size_t i= ; i<NUM_BUILTIN_DISPLAYS ; i++) {
mAllocatedDisplayIDs.markBit(i);
} if (mHwc) {
ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
(hwcApiVersion(mHwc) >> ) & 0xff,
(hwcApiVersion(mHwc) >> ) & 0xff);
if (mHwc->registerProcs) {
mCBContext->hwc = this;
mCBContext->procs.invalidate = &hook_invalidate;
mCBContext->procs.vsync = &hook_vsync;
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
mCBContext->procs.hotplug = &hook_hotplug;
else
mCBContext->procs.hotplug = NULL;
memset(mCBContext->procs.zero, , sizeof(mCBContext->procs.zero));
mHwc->registerProcs(mHwc, &mCBContext->procs);
} // don't need a vsync thread if we have a hardware composer
needVSyncThread = false;
// always turn vsync off when we start
eventControl(HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, ); // the number of displays we actually have depends on the
// hw composer version
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
// 1.3 adds support for virtual displays
mNumDisplays = MAX_HWC_DISPLAYS;
} else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
// 1.1 adds support for multiple displays
mNumDisplays = NUM_BUILTIN_DISPLAYS;
} else {
mNumDisplays = ;
}
} if (mFbDev) {
ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
"should only have fbdev if no hwc or hwc is 1.0"); DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
disp.connected = true;
disp.format = mFbDev->format;
DisplayConfig config = DisplayConfig();
config.width = mFbDev->width;
config.height = mFbDev->height;
config.xdpi = mFbDev->xdpi;
config.ydpi = mFbDev->ydpi;
#ifdef QCOM_BSP
config.secure = true; //XXX: Assuming primary is always true
#endif
config.refresh = nsecs_t(1e9 / mFbDev->fps);
disp.configs.push_back(config);
disp.currentConfig = ;
} else if (mHwc) {
// here we're guaranteed to have at least HWC 1.1
for (size_t i = ; i<NUM_BUILTIN_DISPLAYS ; i++) {
queryDisplayProperties(i);
}
} // read system property for VDS solution
// This property is expected to be setup once during bootup
if( (property_get("persist.hwc.enable_vds", value, NULL) > ) &&
((!strncmp(value, "", strlen(""))) ||
!strncasecmp(value, "true", strlen("true")))) {
//HAL virtual display is using VDS based implementation
mVDSEnabled = true;
} if (needVSyncThread) {
// we don't have VSYNC support, we need to fake it
mVSyncThread = new VSyncThread(*this);
}
#ifdef QCOM_BSP
// Threshold Area to enable GPU Tiled Rect.
property_get("debug.hwc.gpuTiledThreshold", value, "1.9");
mDynThreshold = atof(value);
#endif
}

HWComposer

bool needVSyncThread = true;

是否需要模拟产生VSync信号,默认是开启的。

  // Note: some devices may insist that the FB HAL be opened before HWC.
int fberr = loadFbHalModule();
loadHwcModule();

打开fb & hwc设备的HAL模块。

        if (mHwc->registerProcs) {
mCBContext->hwc = this;
mCBContext->procs.invalidate = &hook_invalidate;
mCBContext->procs.vsync = &hook_vsync;
if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
mCBContext->procs.hotplug = &hook_hotplug;
else
mCBContext->procs.hotplug = NULL;
memset(mCBContext->procs.zero, , sizeof(mCBContext->procs.zero));
mHwc->registerProcs(mHwc, &mCBContext->procs);
} // don't need a vsync thread if we have a hardware composer
needVSyncThread = false;

硬件VSync信号启动,不需要软件模拟。

    if (needVSyncThread) {
// we don't have VSYNC support, we need to fake it
mVSyncThread = new VSyncThread(*this);
}

如果需要,启动VSyncThread线程来开启软件模拟。

8.2.1硬件产生

mHwc->registerProcs(mHwc, &mCBContext->procs);

hwc会产生回调:procs.vsync & procs.invalidate 信号。

void HWComposer::vsync(int disp, int64_t timestamp) {
if (uint32_t(disp) < HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
{
Mutex::Autolock _l(mLock); // There have been reports of HWCs that signal several vsync events
// with the same timestamp when turning the display off and on. This
// is a bug in the HWC implementation, but filter the extra events
// out here so they don't cause havoc downstream.
if (timestamp == mLastHwVSync[disp]) {
ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
timestamp);
return;
} mLastHwVSync[disp] = timestamp;
} char tag[];
snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
ATRACE_INT(tag, ++mVSyncCounts[disp] & ); mEventHandler.onVSyncReceived(disp, timestamp);
}
}

最终会通知mEventHandler的消息,这个handler从那里来的呢?

void SurfaceFlinger::init(){

 mHwc = new HWComposer(this,
*static_cast<HWComposer::EventHandler *>(this));
}

Yes,handler就是SurfaceFlinger,对嘛。SurfaceFlinger就是Surface合成的总管,所以这个信号一定会被它接收。

class SurfaceFlinger : public BnSurfaceComposer,
private IBinder::DeathRecipient,
private HWComposer::EventHandler
 

8.2.2软件模拟信号

bool HWComposer::VSyncThread::threadLoop() {
{ // scope for lock
Mutex::Autolock _l(mLock);
while (!mEnabled) {
mCondition.wait(mLock);
}
} const nsecs_t period = mRefreshPeriod;
const nsecs_t now = systemTime(CLOCK_MONOTONIC);
nsecs_t next_vsync = mNextFakeVSync;
nsecs_t sleep = next_vsync - now;
if (sleep < ) {
// we missed, find where the next vsync should be
sleep = (period - ((now - next_vsync) % period));
next_vsync = now + sleep;
}
mNextFakeVSync = next_vsync + period; struct timespec spec;
spec.tv_sec = next_vsync / ;
spec.tv_nsec = next_vsync % ; int err;
do {
err = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &spec, NULL);
} while (err< && errno == EINTR); if (err == ) {
mHwc.mEventHandler.onVSyncReceived(, next_vsync);
} return true;
}

判断系统Vsync信号开关。然后计算下一次刷新的时间点。

 const nsecs_t period = mRefreshPeriod;

刷新间隔,CLOCK_MONOTONIC是从系统开机后的时间间隔(tick累加)

得到需要等待的时间sleep,和下一次vsync信号的时间点。

然后一个do while的操作,来等待信号时间点的到来。

最后,发出这个信号。

这里还有个情况,就是一开始的地方,mEnable变量,系统可以设置enable来控制vsync信号的产生。

void HWComposer::VSyncThread::setEnabled(bool enabled) 

8.3 SurfaceFlinger处理Vsync信号

在4.4以前,Vsync的处理通过EventThread就可以了。但是KK再次对这段逻辑进行细化和复杂化。Google真是费劲心思为了提升性能。

先来直接看下Surfaceflinger的onVSyncReceived函数:

void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
bool needsHwVsync = false; { // Scope for the lock
Mutex::Autolock _l(mHWVsyncLock);
if (type == && mPrimaryHWVsyncEnabled) {
needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);//mPromaryDisplays是什么?
}
} if (needsHwVsync) {
enableHardwareVsync();//做了什么
} else {
disableHardwareVsync(false);//做了什么
  } 

}

虽然很短,但是乍一看还是一头雾水

mPrimaryHWVsyncEnabled是什么时候被赋值的?

mPrimaryDispSync是什么,addResyncSample又做了什么?

enableHardwareVsync &disableHardwareVsync在干什么?

要解答这些问题,就从SurfaceFlinger::init开始看

void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W..."); status_t err;
Mutex::Autolock _l(mStateLock); /* Set the mask bit of the sigset to block the SIGPIPE signal */
sigset_t sigMask;
sigemptyset (&sigMask);
sigaddset(&sigMask, SIGPIPE);
sigprocmask(SIG_BLOCK, &sigMask, NULL); // initialize EGL for the default display
mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(mEGLDisplay, NULL, NULL); // Initialize the H/W composer object. There may or may not be an
// actual hardware composer underneath.
mHwc = new HWComposer(this,
*static_cast<HWComposer::EventHandler *>(this)); // get a RenderEngine for the given display / config (can't fail)
mRenderEngine = RenderEngine::create(mEGLDisplay, mHwc->getVisualID()); // retrieve the EGL context that was selected/created
mEGLContext = mRenderEngine->getEGLContext(); LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
"couldn't create EGLContext"); // initialize our non-virtual displays
for (size_t i= ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
DisplayDevice::DisplayType type((DisplayDevice::DisplayType)i);
// set-up the displays that are already connected
if (mHwc->isConnected(i) || type==DisplayDevice::DISPLAY_PRIMARY) {
#ifdef QCOM_BSP
// query from hwc if the non-virtual display is secure.
bool isSecure = mHwc->isSecure(i);;
#else
// All non-virtual displays are currently considered secure
bool isSecure = true;
#endif
createBuiltinDisplayLocked(type, isSecure);
wp<IBinder> token = mBuiltinDisplays[i]; sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer,
new GraphicBufferAlloc()); sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, i,
consumer);
int32_t hwcId = allocateHwcDisplayId(type);
sp<DisplayDevice> hw = new DisplayDevice(this,
type, hwcId, mHwc->getFormat(hwcId), isSecure, token,
fbs, producer,
mRenderEngine->getEGLConfig());
if (i > DisplayDevice::DISPLAY_PRIMARY) {
// FIXME: currently we don't get blank/unblank requests
// for displays other than the main display, so we always
// assume a connected display is unblanked.
ALOGD("marking display %zu as acquired/unblanked", i);
hw->setPowerMode(HWC_POWER_MODE_NORMAL);
}
mDisplays.add(token, hw);
}
} // make the GLContext current so that we can create textures when creating Layers
// (which may happens before we render something)
getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext); // start the EventThread
sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
vsyncPhaseOffsetNs, true, "app");
mEventThread = new EventThread(vsyncSrc);
sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
sfVsyncPhaseOffsetNs, true, "sf");
mSFEventThread = new EventThread(sfVsyncSrc);
mEventQueue.setEventThread(mSFEventThread); mEventControlThread = new EventControlThread(this);
mEventControlThread->run("EventControl", PRIORITY_URGENT_DISPLAY);
android_set_rt_ioprio(mEventControlThread->getTid(), ); // set a fake vsync period if there is no HWComposer
if (mHwc->initCheck() != NO_ERROR) {
mPrimaryDispSync.setPeriod();
} // initialize our drawing state
mDrawingState = mCurrentState; // set initial conditions (e.g. unblank default device)
initializeDisplays(); // start boot animation
startBootAnim();
}

SurfaceFlinger::init

有2个几乎一样的DispSyncSource,它的目的是提供了Vsync的虚拟化。关于这块的分析,可以参考Android 4.4(KitKat)中VSync信号的虚拟化

在三缓冲的框架下,对于一帧内容,先等APP UI画完了,SurfaceFlinger再出场整合到FrameBuffer

而现在google就是让它们一起跑起来。

然后搞了2个延时,这样就不会有问题。对应vsyncSrc(绘图延时) & sfVsyncSrc(合成延时)

8.3.1 EventThread

bool EventThread::threadLoop() {
DisplayEventReceiver::Event event;
Vector< sp<EventThread::Connection> > signalConnections;
signalConnections = waitForEvent(&event); // dispatch events to listeners...
const size_t count = signalConnections.size();
for (size_t i= ; i<count ; i++) {
const sp<Connection>& conn(signalConnections[i]);
// now see if we still need to report this event
status_t err = conn->postEvent(event);
if (err == -EAGAIN || err == -EWOULDBLOCK) {
// The destination doesn't accept events anymore, it's probably
// full. For now, we just drop the events on the floor.
// FIXME: Note that some events cannot be dropped and would have
// to be re-sent later.
// Right-now we don't have the ability to do this.
ALOGW("EventThread: dropping event (%08x) for connection %p",
event.header.type, conn.get());
} else if (err < ) {
// handle any other error on the pipe as fatal. the only
// reasonable thing to do is to clean-up this connection.
// The most common error we'll get here is -EPIPE.
removeDisplayEventConnection(signalConnections[i]);
}
}
return true;
}

EventThread会发送消息到surfaceflinger里面的MessageQueue。

MessageQueue处理消息:

int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
ssize_t n;
DisplayEventReceiver::Event buffer[];
while ((n = DisplayEventReceiver::getEvents(mEventTube, buffer, )) > ) {
for (int i= ; i<n ; i++) {
if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
#if INVALIDATE_ON_VSYNC
mHandler->dispatchInvalidate();
#else
mHandler->dispatchRefresh();
#endif
break;
}
}
}
return ;
}

如果Event的类型是

DisplayEventReceiver::DISPLAY_EVENT_VSYNC

正是我们需要的类型,所以,就有2中处理方式:

UI进程需要先准备好数据(invalidate),然后Vsync信号来了以后,就开始刷新屏幕。

SurfaceFlinger是在Vsync来临之际准备数据然后刷新,还是平常就准备当VSync来临是再刷新。

先来看dispatchInvalidate,最后处理的地方就是这里。

        case MessageQueue::INVALIDATE: {
bool refreshNeeded = handleMessageTransaction();
refreshNeeded |= handleMessageInvalidate();
refreshNeeded |= mRepaintEverything;
if (refreshNeeded) {
// Signal a refresh if a transaction modified the window state,
// a new buffer was latched, or if HWC has requested a full
// repaint
signalRefresh();
}
break;
}

我们来看下handleMessageRefresh:

void SurfaceFlinger::handleMessageRefresh() {
ATRACE_CALL();
preComposition();  //合成前的准备
rebuildLayerStacks();//重新建立layer堆栈
setUpHWComposer();//HWComposer的设定
#ifdef QCOM_BSP
setUpTiledDr();
#endif
doDebugFlashRegions();
doComposition();  //正式合成工作
postComposition(); //合成的后期工作
}

8.3.2handleMessageTransaction

handleMessageTransaction在简单判断后直接调用handlerTransaction。

可以看到里面的handleTransactionLocked才是代码真正处理的地方。

void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
const LayerVector& currentLayers(mCurrentState.layersSortedByZ);
const size_t count = currentLayers.size(); /*
* Traversal of the children
* (perform the transaction for each of them if needed)
*/ if (transactionFlags & eTraversalNeeded) {
for (size_t i= ; i<count ; i++) {
const sp<Layer>& layer(currentLayers[i]);
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) continue; const uint32_t flags = layer->doTransaction();
if (flags & Layer::eVisibleRegion)
mVisibleRegionsDirty = true;
}
} /*
* Perform display own transactions if needed
*/ if (transactionFlags & eDisplayTransactionNeeded) {
// here we take advantage of Vector's copy-on-write semantics to
// improve performance by skipping the transaction entirely when
// know that the lists are identical
const KeyedVector< wp<IBinder>, DisplayDeviceState>& curr(mCurrentState.displays);
const KeyedVector< wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays);
if (!curr.isIdenticalTo(draw)) {
mVisibleRegionsDirty = true;
const size_t cc = curr.size();
size_t dc = draw.size(); // find the displays that were removed
// (ie: in drawing state but not in current state)
// also handle displays that changed
// (ie: displays that are in both lists)
for (size_t i= ; i<dc ; i++) {
const ssize_t j = curr.indexOfKey(draw.keyAt(i));
if (j < ) {
// in drawing state but not in current state
if (!draw[i].isMainDisplay()) {
// Call makeCurrent() on the primary display so we can
// be sure that nothing associated with this display
// is current.
const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDevice());
defaultDisplay->makeCurrent(mEGLDisplay, mEGLContext);
sp<DisplayDevice> hw(getDisplayDevice(draw.keyAt(i)));
if (hw != NULL)
hw->disconnect(getHwComposer());
if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
mEventThread->onHotplugReceived(draw[i].type, false);
mDisplays.removeItem(draw.keyAt(i));
} else {
ALOGW("trying to remove the main display");
}
} else {
// this display is in both lists. see if something changed.
const DisplayDeviceState& state(curr[j]);
const wp<IBinder>& display(curr.keyAt(j));
if (state.surface->asBinder() != draw[i].surface->asBinder()) {
// changing the surface is like destroying and
// recreating the DisplayDevice, so we just remove it
// from the drawing state, so that it get re-added
// below.
sp<DisplayDevice> hw(getDisplayDevice(display));
if (hw != NULL)
hw->disconnect(getHwComposer());
mDisplays.removeItem(display);
mDrawingState.displays.removeItemsAt(i);
dc--; i--;
// at this point we must loop to the next item
continue;
} const sp<DisplayDevice> disp(getDisplayDevice(display));
if (disp != NULL) {
if (state.layerStack != draw[i].layerStack) {
disp->setLayerStack(state.layerStack);
}
if ((state.orientation != draw[i].orientation)
|| (state.viewport != draw[i].viewport)
|| (state.frame != draw[i].frame))
{
#ifdef QCOM_BSP
int orient = state.orientation;
// Honor the orientation change after boot
// animation completes and make sure boot
// animation is shown in panel orientation always.
if(mBootFinished){
disp->setProjection(state.orientation,
state.viewport, state.frame);
orient = state.orientation;
}
else{
char property[PROPERTY_VALUE_MAX];
int panelOrientation =
DisplayState::eOrientationDefault;
if(property_get("persist.panel.orientation",
property, "") > ){
panelOrientation = atoi(property) / ;
}
disp->setProjection(panelOrientation,
state.viewport, state.frame);
orient = panelOrientation;
}
// Set the view frame of each display only of its
// default orientation.
if(orient == DisplayState::eOrientationDefault and
state.frame.isValid()) {
qdutils::setViewFrame(disp->getHwcDisplayId(),
state.frame.left, state.frame.top,
state.frame.right, state.frame.bottom);
}
#else
disp->setProjection(state.orientation,
state.viewport, state.frame);
#endif
}
if (state.width != draw[i].width || state.height != draw[i].height) {
disp->setDisplaySize(state.width, state.height);
}
}
}
} // find displays that were added
// (ie: in current state but not in drawing state)
for (size_t i= ; i<cc ; i++) {
if (draw.indexOfKey(curr.keyAt(i)) < ) {
const DisplayDeviceState& state(curr[i]); sp<DisplaySurface> dispSurface;
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferProducer> bqProducer;
sp<IGraphicBufferConsumer> bqConsumer;
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer,
new GraphicBufferAlloc()); int32_t hwcDisplayId = -;
if (state.isVirtualDisplay()) {
// Virtual displays without a surface are dormant:
// they have external state (layer stack, projection,
// etc.) but no internal state (i.e. a DisplayDevice).
if (state.surface != NULL) {
configureVirtualDisplay(hwcDisplayId,
dispSurface, producer, state, bqProducer,
bqConsumer);
}
} else {
ALOGE_IF(state.surface!=NULL,
"adding a supported display, but rendering "
"surface is provided (%p), ignoring it",
state.surface.get());
hwcDisplayId = allocateHwcDisplayId(state.type);
// for supported (by hwc) displays we provide our
// own rendering surface
dispSurface = new FramebufferSurface(*mHwc, state.type,
bqConsumer);
producer = bqProducer;
} const wp<IBinder>& display(curr.keyAt(i));
if (dispSurface != NULL && producer != NULL) {
sp<DisplayDevice> hw = new DisplayDevice(this,
state.type, hwcDisplayId,
mHwc->getFormat(hwcDisplayId), state.isSecure,
display, dispSurface, producer,
mRenderEngine->getEGLConfig());
hw->setLayerStack(state.layerStack);
hw->setProjection(state.orientation,
state.viewport, state.frame);
hw->setDisplayName(state.displayName);
// When a new display device is added update the active
// config by querying HWC otherwise the default config
// (config 0) will be used.
int activeConfig = mHwc->getActiveConfig(hwcDisplayId);
if (activeConfig >= ) {
hw->setActiveConfig(activeConfig);
}
mDisplays.add(display, hw);
if (state.isVirtualDisplay()) {
if (hwcDisplayId >= ) {
mHwc->setVirtualDisplayProperties(hwcDisplayId,
hw->getWidth(), hw->getHeight(),
hw->getFormat());
}
} else {
mEventThread->onHotplugReceived(state.type, true);
}
}
}
}
}
} if (transactionFlags & (eTraversalNeeded|eDisplayTransactionNeeded)) {
// The transform hint might have changed for some layers
// (either because a display has changed, or because a layer
// as changed).
//
// Walk through all the layers in currentLayers,
// and update their transform hint.
//
// If a layer is visible only on a single display, then that
// display is used to calculate the hint, otherwise we use the
// default display.
//
// NOTE: we do this here, rather than in rebuildLayerStacks() so that
// the hint is set before we acquire a buffer from the surface texture.
//
// NOTE: layer transactions have taken place already, so we use their
// drawing state. However, SurfaceFlinger's own transaction has not
// happened yet, so we must use the current state layer list
// (soon to become the drawing state list).
//
sp<const DisplayDevice> disp;
uint32_t currentlayerStack = ;
for (size_t i=; i<count; i++) {
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
const sp<Layer>& layer(currentLayers[i]);
uint32_t layerStack = layer->getDrawingState().layerStack;
if (i== || currentlayerStack != layerStack) {
currentlayerStack = layerStack;
// figure out if this layerstack is mirrored
// (more than one display) if so, pick the default display,
// if not, pick the only display it's on.
disp.clear();
for (size_t dpy= ; dpy<mDisplays.size() ; dpy++) {
sp<const DisplayDevice> hw(mDisplays[dpy]);
if (hw->getLayerStack() == currentlayerStack) {
if (disp == NULL) {
disp = hw;
} else {
disp = NULL;
break;
}
}
}
}
if (disp == NULL) {
// NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
// redraw after transform hint changes. See bug 8508397. // could be null when this layer is using a layerStack
// that is not visible on any display. Also can occur at
// screen off/on times.
disp = getDefaultDisplayDevice();
}
layer->updateTransformHint(disp);
}
} /*
* Perform our own transaction if needed
*/ const LayerVector& layers(mDrawingState.layersSortedByZ);
if (currentLayers.size() > layers.size()) {
// layers have been added
mVisibleRegionsDirty = true;
} // some layers might have been removed, so
// we need to update the regions they're exposing.
if (mLayersRemoved) {
mLayersRemoved = false;
mVisibleRegionsDirty = true;
const size_t count = layers.size();
for (size_t i= ; i<count ; i++) {
const sp<Layer>& layer(layers[i]);
if (currentLayers.indexOf(layer) < ) {
// this layer is not visible anymore
// TODO: we could traverse the tree from front to back and
// compute the actual visible region
// TODO: we could cache the transformed region
const Layer::State& s(layer->getDrawingState());
Region visibleReg = s.transform.transform(
Region(Rect(s.active.w, s.active.h)));
invalidateLayerStack(s.layerStack, visibleReg);
}
}
} commitTransaction(); updateCursorAsync();
}

handleTransactionLocked

这里处理3中情况,过程类似,我们只看eTraversalNeeded这种情况。

 uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);

获取各个layer的标志位,然后做const uint32_t flags = layer->doTransaction(0);的操作

各layer计算各自的可见区域,mVisibleRegionsDirty记录可见区域变化。

以下代码:

mCurrentState.layersSortedByZ

surfaceFlinger有2个记录layer变化的全局变量

State mDrawingState;
State mCurrentState;

一个记录上一次的状态,后者记录当前的状态,这样就可以判断layer的变化状态。layersSortedByZ 可见,layer是通过Z-order排列的。

这个变量记录了所有的layer。

我们来看下

uint32_t Layer::doTransaction(uint32_t flags) {
ATRACE_CALL(); const Layer::State& s(getDrawingState());
const Layer::State& c(getCurrentState()); const bool sizeChanged = (c.requested.w != s.requested.w) ||
(c.requested.h != s.requested.h); if (sizeChanged) {
// the size changed, we need to ask our client to request a new buffer
ALOGD_IF(DEBUG_RESIZE,
"doTransaction: geometry (layer=%p '%s'), tr=%02x, scalingMode=%d\n"
" current={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
this, getName().string(), mCurrentTransform, mCurrentScalingMode,
c.active.w, c.active.h,
c.active.crop.left,
c.active.crop.top,
c.active.crop.right,
c.active.crop.bottom,
c.active.crop.getWidth(),
c.active.crop.getHeight(),
c.requested.w, c.requested.h,
c.requested.crop.left,
c.requested.crop.top,
c.requested.crop.right,
c.requested.crop.bottom,
c.requested.crop.getWidth(),
c.requested.crop.getHeight(),
s.active.w, s.active.h,
s.active.crop.left,
s.active.crop.top,
s.active.crop.right,
s.active.crop.bottom,
s.active.crop.getWidth(),
s.active.crop.getHeight(),
s.requested.w, s.requested.h,
s.requested.crop.left,
s.requested.crop.top,
s.requested.crop.right,
s.requested.crop.bottom,
s.requested.crop.getWidth(),
s.requested.crop.getHeight()); // record the new size, form this point on, when the client request
// a buffer, it'll get the new size.
mSurfaceFlingerConsumer->setDefaultBufferSize(
c.requested.w, c.requested.h);
} if (!isFixedSize()) { const bool resizePending = (c.requested.w != c.active.w) ||
(c.requested.h != c.active.h); if (resizePending) {
// don't let Layer::doTransaction update the drawing state
// if we have a pending resize, unless we are in fixed-size mode.
// the drawing state will be updated only once we receive a buffer
// with the correct size.
//
// in particular, we want to make sure the clip (which is part
// of the geometry state) is latched together with the size but is
// latched immediately when no resizing is involved. flags |= eDontUpdateGeometryState;
}
} // always set active to requested, unless we're asked not to
// this is used by Layer, which special cases resizes.
if (flags & eDontUpdateGeometryState) {
} else {
Layer::State& editCurrentState(getCurrentState());
editCurrentState.active = c.requested;
} if (s.active != c.active) {
// invalidate and recompute the visible regions if needed
flags |= Layer::eVisibleRegion;
} if (c.sequence != s.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;
this->contentDirty = true; // we may use linear filtering, if the matrix scales us
const uint8_t type = c.transform.getType();
mNeedsFiltering = (!c.transform.preserveRects() ||
(type >= Transform::SCALE));
} // Commit the transaction
commitTransaction();
return flags;
}

首先判断size是否有修改,然后

mSurfaceFlingerConsumer->setDefaultBufferSize

重新获取大小。

if (c.sequence != s.sequence) {
// invalidate and recompute the visible regions if needed
flags |= eVisibleRegion;

Sequence是个什么东西?

当Layer的position,Zorder,alpha,matrix,transparent region,flags,crops.等发生变化的时候,sequence就会自增。

也就是,当这些属性发生变化是,页面在Vsync信号触发的时候,根据sequence来判断是否需要属性页面。

新增layer,

对比2个state中的layer队列,就可以知道新增的layer。

移除layer,

也是比较2个layer队列,就可以找到移除的layer。

提交transaction,主要就是同步2个state。然后currentstate继续跟踪layer变化,如此往复。

Vsync 是SurfaceFlinger模块最核心的概念,所以这块将会分多次讲解。

最新文章

  1. Flash Air 打包安卓 ane
  2. 《boot分区监控的小脚本》
  3. js与asp.net后台交互
  4. tap/click on search button on softkeyboard
  5. 学习笔记之JAVA多线程
  6. jsp(一) : servlet基础
  7. which命令
  8. io端口
  9. MYSQL高可用(HA)随想
  10. memcached+tomcat转发forward时 sessionid一直变化的问题
  11. 使用PHP画统计图的方法
  12. java效验只能为数字类型
  13. 简单ATM系统
  14. 启动aspx文件错误
  15. em,px,rem的区别
  16. LoadRunner进行参数化的九种方式取值和连接数据库取值
  17. websocket 工作原理
  18. The zero inflated negative binomial distribution
  19. EditPlus 3安装的配置操作
  20. Codeforces 711E ZS and The Birthday Paradox 数学

热门文章

  1. 【SQL】找出行数与自增标识值不相等的表(即有缺行)
  2. iOS版本比较方法
  3. 聊一下C#开发者如何过渡到JAVA 开发者
  4. input框中的size和maxlength的区别
  5. Rest风格中关于JPA使用懒加载的坑
  6. apache tiles 页面模板的使用
  7. sp_get_menu函数使用分析
  8. Git远程和分支管理
  9. windows 7/10下安装oracle 10g
  10. spring amqp rabbitmq fanout配置