SurfaceFlinger多Display管理

来源:互联网 发布:什么软件有淘宝优惠卷 编辑:程序博客网 时间:2024/06/05 06:42

c++打开log #define LOG_NDEBUG 0

1 SurfaceFlinger::init()->new HWComposer()
HWComposer 里面包含一个BitSet32 mAllocatedDisplayIDs 数据结构用于管理已经分配的display.
HWComposer初始化的过程中会默认创建NUM_BUILTIN_DISPLAYS(2)个设备ID. 

据官方说法在设备注册热插拔函数后要立即收到主设备的热插拔事件.在设备的正常操作期间,除了主显示设备之外,仅可热插拔一个外部显示设备。
最多有三种类型设备分别如下
HWC_DISPLAY_PRIMARY = 0,
HWC_DISPLAY_EXTERNAL = 1, // HDMI, DP, etc.
HWC_DISPLAY_VIRTUAL = 2,

对于HWC_1.1版本之前的设备,这种设备直接使用FrameBuffer信息初始化HWC_DISPLAY_PRIMARY的DisplayData,如下

     disp.format = mFbDev->format;        DisplayConfig config = DisplayConfig();        config.width = mFbDev->width;        config.height = mFbDev->height;        config.xdpi = mFbDev->xdpi;        config.ydpi = mFbDev->ydpi;        config.refresh = nsecs_t(1e9 / mFbDev->fps);        disp.configs.push_back(config);        disp.currentConfig = 0;

直接使用gralloc驱动中探测到的设备信息初始化primary屏幕信息

对于HWC_1.1+的设备,使用queryDisplayProperties去通过hwc驱动查询设备信息,这里初始化NUM_BUILTIN_DISPLAYS两个设备的信息
  

status_t HWComposer::queryDisplayProperties(int disp) {    LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));    // use zero as default value for unspecified attributes    int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];    memset(values, 0, sizeof(values));    const size_t MAX_NUM_CONFIGS = 128;    uint32_t configs[MAX_NUM_CONFIGS] = {0};    size_t numConfigs = MAX_NUM_CONFIGS;    status_t err = mHwc->getDisplayConfigs(mHwc, disp, configs, &numConfigs);    if (err != NO_ERROR) {        // this can happen if an unpluggable display is not connected        mDisplayData[disp].connected = false;        return err;    }    mDisplayData[disp].currentConfig = 0;    for (size_t c = 0; c < numConfigs; ++c) {        err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],                DISPLAY_ATTRIBUTES, values);        // If this is a pre-1.5 HWC, it may not know about color transform, so        // try again with a smaller set of attributes        if (err != NO_ERROR) {            err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],                    PRE_HWC15_DISPLAY_ATTRIBUTES, values);        }        if (err != NO_ERROR) {            // we can't get this display's info. turn it off.            mDisplayData[disp].connected = false;            return err;        }        DisplayConfig config = DisplayConfig();        for (size_t i = 0; i < NUM_DISPLAY_ATTRIBUTES - 1; i++) {            switch (DISPLAY_ATTRIBUTES[i]) {                case HWC_DISPLAY_VSYNC_PERIOD:                    config.refresh = nsecs_t(values[i]);                    break;                case HWC_DISPLAY_WIDTH:                    config.width = values[i];                    break;                case HWC_DISPLAY_HEIGHT:                    config.height = values[i];                    break;                case HWC_DISPLAY_DPI_X:                    config.xdpi = values[i] / 1000.0f;                    break;                case HWC_DISPLAY_DPI_Y:                    config.ydpi = values[i] / 1000.0f;                    break;                case HWC_DISPLAY_COLOR_TRANSFORM:                    config.colorMode = static_cast<android_color_mode_t>(values[i]);                    break;                default:                    ALOG_ASSERT(false, "unknown display attribute[%zu] %#x",                            i, DISPLAY_ATTRIBUTES[i]);                    break;            }        }        if (config.xdpi == 0.0f || config.ydpi == 0.0f) {            float dpi = getDefaultDensity(config.width, config.height);            config.xdpi = dpi;            config.ydpi = dpi;        }        mDisplayData[disp].configs.push_back(config);    }    // FIXME: what should we set the format to?    mDisplayData[disp].format = HAL_PIXEL_FORMAT_RGBA_8888;    mDisplayData[disp].connected = true;    return NO_ERROR;}

通过getDisplayConfigs查询设备支持的configure,这个函数也比较简单,查出多个configure,设置属性,并设置currentConfig=0
设置format = HAL_PIXEL_FORMAT_RGBA_8888 mDisplayData[disp].connected = true
其实这里如果没有插入其他设备的话只能读到第一个设备的属性信息,也就是只连接了一个设备

2 SurfaceFlinger::init()  创建DisplayDevice的过程
首先使用createBuiltinDisplayLocked函数创建两个内建设备的状态

void SurfaceFlinger::createBuiltinDisplayLocked(DisplayDevice::DisplayType type) {    ALOGW_IF(mBuiltinDisplays[type],            "Overwriting display token for display type %d", type);    mBuiltinDisplays[type] = new BBinder();    // All non-virtual displays are currently considered secure.    DisplayDeviceState info(type, true);    mCurrentState.displays.add(mBuiltinDisplays[type], info);}

为每个内建设备创建DisplayDevice数据结构 记录设备信息
      

 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);

这里边创建生产者消费者没有什么好说的,还创建了FramebuffersSurface 作为DisplayDevice的displaySurface
http://blog.csdn.net/ouo555/article/details/44340785
FramebuffersSurface与SurfaceFlingerConsumer一样都是用于包装消费者的,不同点在于SurfaceFlingerConsumer用于最终的图像合成.
最后如果是第一个设备则设置powerMode为NORMAL,放入devices队列

我们来看看设备构造的过程

DisplayDevice::DisplayDevice(        const sp<SurfaceFlinger>& flinger,        DisplayType type,        int32_t hwcId,#ifndef USE_HWC2        int format,#endif        bool isSecure,        const wp<IBinder>& displayToken,        const sp<DisplaySurface>& displaySurface,        const sp<IGraphicBufferProducer>& producer,        EGLConfig config)    : lastCompositionHadVisibleLayers(false),      mFlinger(flinger),      mType(type),      mHwcDisplayId(hwcId),      mDisplayToken(displayToken),      mDisplaySurface(displaySurface),      mDisplay(EGL_NO_DISPLAY),      mSurface(EGL_NO_SURFACE),      mDisplayWidth(),      mDisplayHeight(),#ifndef USE_HWC2      mFormat(),#endif      mFlags(),      mPageFlipCount(),      mIsSecure(isSecure),      mLayerStack(NO_LAYER_STACK),      mOrientation(),      mPowerMode(HWC_POWER_MODE_OFF),      mActiveConfig(0){    Surface* surface;    mNativeWindow = surface = new Surface(producer, false);    ANativeWindow* const window = mNativeWindow.get();    /*     * Create our display's surface     */
    EGLSurface eglSurface;    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);    if (config == EGL_NO_CONFIG) {#ifdef USE_HWC2        config = RenderEngine::chooseEglConfig(display, PIXEL_FORMAT_RGBA_8888);#else        config = RenderEngine::chooseEglConfig(display, format);#endif    }    eglSurface = eglCreateWindowSurface(display, config, window, NULL);    eglQuerySurface(display, eglSurface, EGL_WIDTH,  &mDisplayWidth);    eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight);    // Make sure that composition can never be stalled by a virtual display    // consumer that isn't processing buffers fast enough. We have to do this    // in two places:    // * Here, in case the display is composed entirely by HWC.    // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the    //   window's swap interval in eglMakeCurrent, so they'll override the    //   interval we set here.    if (mType >= DisplayDevice::DISPLAY_VIRTUAL)        window->setSwapInterval(window, 0);    mConfig = config;    mDisplay = display;    mSurface = eglSurface;#ifndef USE_HWC2    mFormat = format;#endif    mPageFlipCount = 0;    mViewport.makeInvalid();    mFrame.makeInvalid();    // virtual displays are always considered enabled    mPowerMode = (mType >= DisplayDevice::DISPLAY_VIRTUAL) ?                  HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;    // Name the display.  The name will be replaced shortly if the display    // was created with createDisplay().    switch (mType) {        case DISPLAY_PRIMARY:            mDisplayName = "Built-in Screen";            break;        case DISPLAY_EXTERNAL:            mDisplayName = "HDMI Screen";            break;        default:            mDisplayName = "Virtual Screen";    // e.g. Overlay #n            break;    }    // initialize the display orientation transform.    setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);#ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS    surface->allocateBuffers();#endif}

之后设备就算初始化好了 执行SurfaceFlinger::onInitializeDisplays()
这个函数主要做了两件事情
1 setTransactionState更新事务状态 主要更新mCurrentState中的display状态和tranfactionFlags
2 setPowerModeInternal 设置powerMode为HWC_POWER_MODE_NORMAL
  

if (currentMode == HWC_POWER_MODE_OFF) {        // Turn on the display        getHwComposer().setPowerMode(type, mode);        if (type == DisplayDevice::DISPLAY_PRIMARY) {            // FIXME: eventthread only knows about the main display right now            mEventThread->onScreenAcquired();            resyncToHardwareVsync(true);        }        mVisibleRegionsDirty = true;        mHasPoweredOff = true;        repaintEverything();        struct sched_param param = {0};        param.sched_priority = 1;        if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {            ALOGW("Couldn't set SCHED_FIFO on display on");        }    } else if (mode == HWC_POWER_MODE_OFF) {        // Turn off the display        struct sched_param param = {0};        if (sched_setscheduler(0, SCHED_OTHER, &param) != 0) {            ALOGW("Couldn't set SCHED_OTHER on display off");        }        if (type == DisplayDevice::DISPLAY_PRIMARY) {            disableHardwareVsync(true); // also cancels any in-progress resync            // FIXME: eventthread only knows about the main display right now            mEventThread->onScreenReleased();        }        getHwComposer().setPowerMode(type, mode);        mVisibleRegionsDirty = true;        // from this point on, SF will stop drawing on this display    } else {        getHwComposer().setPowerMode(type, mode);    }

这里包含三种状态的变换
1 从HWC_POWER_MODE_OFF状态到其他状态,也就是从灭屏幕不可见到可见,需要设置mVisibleRegionsDirty = true 重新绘制,mHasPoweredOff = true,这样绘制的时候就知道是从灭屏到亮屏幕第一次绘制时候使用
设置mRepaintEverything=1 ,表示重新绘制所有layer,设置调度优先级. 还要重新设置硬件发出vsync 校准vsync模型 开启vsync信号
2 由亮屏到灭屏幕 设置mVisibleRegionsDirty 关闭vsync  
3 其他变化 直接设置设备的powermode

3 热插拔过程
先来分析热插过程 

void HWComposer::hotplug(int disp, int connected) {    if (disp >= VIRTUAL_DISPLAY_ID_BASE) {        ALOGE("hotplug event received for invalid display: disp=%d connected=%d",                disp, connected);        return;    }    queryDisplayProperties(disp);    // Do not teardown or recreate the primary display    if (disp != HWC_DISPLAY_PRIMARY) {        mEventHandler.onHotplugReceived(disp, bool(connected));    }}

也是先判断虚拟设备不支持热插,然后查询设备属性,这个过程我们前面分析过,这个过程查询属性封装成mDisplayData保存在HWComposer的mDisplayData里面
然后调用mEventHandler.onHotplugReceived(disp, bool(connected)) 函数通知事件,这个接收者就是surfaceflinger

void SurfaceFlinger::onHotplugReceived(int type, bool connected) {    if (mEventThread == NULL) {        // This is a temporary workaround for b/7145521.  A non-null pointer        // does not mean EventThread has finished initializing, so this        // is not a correct fix.        ALOGW("WARNING: EventThread not started, ignoring hotplug");        return;    }    if (uint32_t(type) < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {        Mutex::Autolock _l(mStateLock);        if (connected) {            createBuiltinDisplayLocked((DisplayDevice::DisplayType)type);        } else {            mCurrentState.displays.removeItem(mBuiltinDisplays[type]);            mBuiltinDisplays[type].clear();        }        setTransactionFlags(eDisplayTransactionNeeded);        // Defer EventThread notification until SF has updated mDisplays.    }}

1如果是连接设备使用createBuiltinDisplayLocked函数创建DisplayDeviceState函数放入mCurrentState,
注意这里并没有创建DisplayDevice设备信息,而是等待执行事务的时候创建设备,所以一会我们会看到添加事务的过程
2如果是设备移除的通知则删除DisplayDevice和DisplayDeviceState信息

最后根据display变化情况创建事务
setTransactionFlags(eDisplayTransactionNeeded) 
这里设置了eDisplayTransactionNeeded的标志,并通知刷新设备信息,我们来看下eDisplayTransactionNeeded怎么处理,代码比较长 我们分段来看

代码在void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)函数里面

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)) {

我们要分析的代码就在满足了这个条件的代码块里面,这里面注释说利用vector的写时复制语义判断数组有没有改变,也就是isIdenticalTo函数,由于mDrawingState是之前的mCurrentState反转而来,所以
反转以后mCurrentState如果没有被写,isIdenticalTo返回true ,既然displaystate没有发生变化就没有必要做任何操作了. 我们这里由于添加了设备所以必然条件成立

       // 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=0 ; i<dc ; i++) {                const ssize_t j = curr.indexOfKey(draw.keyAt(i));                   if (j < 0) {      //第一部分 c                    // 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));                    const sp<IBinder> state_binder = IInterface::asBinder(state.surface);                    const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);                    if (state_binder != draw_binder) {                        // 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))                        {                            disp->setProjection(state.orientation,                                    state.viewport, state.frame);                        }                        if (state.width != draw[i].width || state.height != draw[i].height) {                            disp->setDisplaySize(state.width, state.height);                        }                    }                }            }

先看第一部分: in drawing state but not in current stat,说明该设备被移除了,如果不是main display ,才会处理,否则只会打印log.因为移除了就没的用了.
对于不是主显示设备的移除,首先调用主显示设备的makeCurrent方法,重新初始化elg上下文.然后disconnect要移除的设备,发送onHotplugReceived消息给关心该消息的人

第二部分this display is in both lists. see if something changed,连个队列都包含该设备,所以可能是有一些属性发生了变化
首先如果state_binder发生变化 说明设备已经重新创建,disconnect旧的,和移除displaydevice(因为一会要重建),如果设备没有重新创建,就要更新设备的一下属性:
layerStack,orientation,viewport,frame,width,height
 

    // find displays that were added            // (ie: in current state but not in drawing state)            for (size_t i=0 ; i<cc ; i++) {                if (draw.indexOfKey(curr.keyAt(i)) < 0) {                    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 = -1;                    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) {                            int width = 0;                            int status = state.surface->query(                                    NATIVE_WINDOW_WIDTH, &width);                            ALOGE_IF(status != NO_ERROR,                                    "Unable to query width (%d)", status);                            int height = 0;                            status = state.surface->query(                                    NATIVE_WINDOW_HEIGHT, &height);                            ALOGE_IF(status != NO_ERROR,                                    "Unable to query height (%d)", status);                            if (mUseHwcVirtualDisplays &&                                    (MAX_VIRTUAL_DISPLAY_DIMENSION == 0 ||                                    (width <= MAX_VIRTUAL_DISPLAY_DIMENSION &&                                     height <= MAX_VIRTUAL_DISPLAY_DIMENSION))) {                                hwcDisplayId = allocateHwcDisplayId(state.type);                            }                            sp<VirtualDisplaySurface> vds = new VirtualDisplaySurface(                                    *mHwc, hwcDisplayId, state.surface,                                    bqProducer, bqConsumer, state.displayName);                            dispSurface = vds;                            producer = vds;                        }                    } 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) {                        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);                        mDisplays.add(display, hw);                        if (state.isVirtualDisplay()) {                            if (hwcDisplayId >= 0) {                                mHwc->setVirtualDisplayProperties(hwcDisplayId,                                        hw->getWidth(), hw->getHeight(),                                        hw->getFormat());                            }                        } else {                            mEventThread->onHotplugReceived(state.type, true);                        }                    }                }            }

这里面就是处理新增的设备,还有前面recreate的设备,因为已经从drawState的displays中移除,这里也被认为是新的设备
首先第一步就是为设备创建生产者消费者,然后用surface包装生产者,对于虚拟设备使用VirtualDisplaySurface包装生产者,
物理设备则使用FramebufferSurface包装.
第二部分则是创建DisplayDevice节点

创建的过程 未完待续

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手机螺丝刀 多功能扳手 厨房置物架 kujin 五静 角阀 厨房挂件 锁具大全 毛巾架 落地晾衣架 厨房收纳架 升降衣架 拉篮 地漏 冲压件厂 丝吉利娅门窗五金 五株钱 五铢钱 汉五铢 隋五铢 太和五铢 五铢钱值多少钱 五铢钱价格及图片 魏五铢 废五铢而改铸开元通宝 锱铢必较 更始五铢 汉代五铢钱值568000 汉代五铢钱 五铢铜钱图片及价格 五铢钱价格 五铢铜钱价格 五铢钱罕见的是那一种 汉五铢价格 汉代五铢钱价格及图片 西汉五铢钱价格多少 常平五铢价格 汉五铢图片价格 五铢 五珠钱