android Gui系统之SurfaceFlinger(4)---Vsync(1)
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模块最核心的概念,所以这块将会分多次讲解。
android Gui系统之SurfaceFlinger(4)---Vsync(1)的更多相关文章
- android Gui系统之SurfaceFlinger(5)---Vsync(2)
9.Vsync第二部分 在上一篇中我们讲到,视图的刷新需要很多步骤, void SurfaceFlinger::handleMessageRefresh() { ATRACE_CALL(); preC ...
- android Gui系统之SurfaceFlinger(3)---SurfaceFlinger
7.SurfaceFlinger SurfaceFlinger在前面的篇幅了,多有涉及. SurfaceFlinger是GUI刷新UI的核心,所以任何关于SurfaceFlinger的改进都会对and ...
- android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论
GUI 是任何系统都很重要的一块. android GUI大体分为4大块. 1)SurfaceFlinger 2)WMS 3)View机制 4)InputMethod 这块内容非常之多,但是理解后,可 ...
- android Gui系统之SurfaceFlinger(1)---SurfaceFlinger概论【转】
转自:https://www.cnblogs.com/deman/p/5584198.html 阅读目录 1.OpenGL & OpenGL ES 2.Android的硬件接口HAL 3.An ...
- android Gui系统之SurfaceFlinger(2)---BufferQueue
6 BufferQueue 上一篇已经说到,BufferQueue是SurfaceFlinger管理和消费surface的中介,我们就开始分析bufferqueue. 每个应用 可以由几个Buffer ...
- 图解Android - Android GUI 系统 (2) - 窗口管理 (View, Canvas, Window Manager)
Android 的窗口管理系统 (View, Canvas, WindowManager) 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道And ...
- Android GUI系统
图解Android - Android GUI 系统 (1) - 概论 图解Android - Android GUI 系统 (2) - 窗口管理系统 图解Android - Android GUI ...
- 图解Android - System Service 概论 和 Android GUI 系统
通过 图解Android - Binder 和 Service 一文中,我们已经分析了Binder 和 Service的工作原理.接下来,我们来简要分析Android 系统里面都有哪些重要的Servi ...
- 图解Android - Android GUI 系统 (1) - 概论
Android的GUI系统是Android最重要也最复杂的系统之一.它包括以下部分: 窗口和图形系统 - Window and View Manager System. 显示合成系统 - Surfac ...
随机推荐
- "Hello World!" for Microsoft Windows
"Hello World!" for Microsoft Windows It's time to write your first application! The follow ...
- 基于TCP和多线程实现无线鼠标键盘-Socket(1)
把手机作为移动鼠标.键盘使用非常方便,本文将实现这一功能.该应用分为两部分:Windows服务端和Android客户端. 本文源代码的下载地址:http://download.csdn.net/det ...
- 【转】php中XML、XSLT的结合运用
原文:http://blog.csdn.net/bjbs_270/article/details/140253 下面我要讲的是一个简单的从数据库中抽取数据,生成XML文档,使用XSLT转换成HTM ...
- 自学H5第二天
笔记: 1.css之外联样式 2.css之行间样式: 3.css之内联样式 二.边框的知识: 1.边框的复合样式: 2.边框的单一样式: /*单一样式*/ border-width: 1px 2px ...
- [moka同学笔记]Yii2.0给一张表中增加一个属性
1.model中建立关联 public function getUser(){ return$this->hasOne(User::className(),['id'=>'uid']) ; ...
- 腾讯信鸽推送Android SDK快速指南
信鸽Android SDK是一个能够提供Push服务的开发平台,提供给开发者简便.易用的API接口,方便快速接入.目前支持Android 2.2及以上版本系统.本文档将引导用户以最快的速度嵌入信鸽SD ...
- python处理ha文件
ha.txt文件内容: frontend oldboy.org bind 0.0.0.0:80 option httplog option httpclose option forwardfor lo ...
- mysql 常用
create database jobs;grant all on jobs.* to root@'%' identified by '111111';flush privileges;
- Linux IO函数的使用和区别
Linux系统中的IO函数主要有read.write.recv.send.recvmsg.sendmsg.readv.writev,本篇主要介绍他们的使用以及区别. read函数: #include ...
- C# 泛型的协变和逆变
1. 可变性的类型:协变性和逆变性 可变性是以一种类型安全的方式,将一个对象当做另一个对象来使用.如果不能将一个类型替换为另一个类型,那么这个类型就称之为:不变量.协变和逆变是两个相互对立的概念: 如 ...