• Sprite Surface 创建 

       鼠标在Android中被称为了Sprite,其Surface的创建是在SpriteController.cpp,目录/frameworks/base/services/input/SpriteController.cpp,那么Sprite对应的图片在哪儿呢,肯定有一个地方会去加载对应分辨率的cursor图片;由frameworks/base/core/java/android/view/PointerIcon.java中的getSystemIcon()导入,然后再由SpriteController::SpriteImpl::setIcon(),设置为Sprite这个精灵的资源。每次鼠标移动后,InputReader线程总会获取这个坐标值,然后InputDispatch会分发给WindowManagerService,而ViewRootImpl会读取等等

       鼠标也是Pointer,在input目录下面还有一个PointerController,这个应该是控制鼠标的,继承自PointerControllerInterface

/** * Interface for tracking a mouse / touch pad pointer and touch pad spots. * * The spots are sprites on screen that visually represent the positions of * fingers * * The pointer controller is responsible for providing synchronization and for tracking * display orientation changes if needed. */class PointerControllerInterface : public virtual RefBase {

 更新鼠标及创建Surface的地方是在SpriteController的SpriteController::doUpdateSprites()中

void SpriteController::doUpdateSprites() {    // Collect information about sprite updates.    // Each sprite update record includes a reference to its associated sprite so we can    // be certain the sprites will not be deleted while this function runs.  Sprites    // may invalidate themselves again during this time but we will handle those changes    // in the next iteration.    Vector updates;    size_t numSprites;    { // acquire lock        AutoMutex _l(mLock);        numSprites = mLocked.invalidatedSprites.size();        for (size_t i = 0; i < numSprites; i++) {            const sp& sprite = mLocked.invalidatedSprites.itemAt(i);            updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));            sprite->resetDirtyLocked();        }        mLocked.invalidatedSprites.clear();    } // release lock    // Create missing surfaces.    bool surfaceChanged = false;    for (size_t i = 0; i < numSprites; i++) {        SpriteUpdate& update = updates.editItemAt(i);        if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {            update.state.surfaceWidth = update.state.icon.bitmap.width();            update.state.surfaceHeight = update.state.icon.bitmap.height();            update.state.surfaceDrawn = false;            update.state.surfaceVisible = false;            update.state.surfaceControl = obtainSurface(                    update.state.surfaceWidth, update.state.surfaceHeight);            if (update.state.surfaceControl != NULL) {                update.surfaceChanged = surfaceChanged = true;            }        }    }    // Resize sprites if needed, inside a global transaction.    bool haveGlobalTransaction = false;    for (size_t i = 0; i < numSprites; i++) {        SpriteUpdate& update = updates.editItemAt(i);        if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {            int32_t desiredWidth = update.state.icon.bitmap.width();            int32_t desiredHeight = update.state.icon.bitmap.height();            if (update.state.surfaceWidth < desiredWidth                    || update.state.surfaceHeight < desiredHeight) {                if (!haveGlobalTransaction) {                    SurfaceComposerClient::openGlobalTransaction();                    haveGlobalTransaction = true;                }                status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight);                if (status) {                    ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d",                            status, update.state.surfaceWidth, update.state.surfaceHeight,                            desiredWidth, desiredHeight);                } else {                    update.state.surfaceWidth = desiredWidth;                    update.state.surfaceHeight = desiredHeight;                    update.state.surfaceDrawn = false;                    update.surfaceChanged = surfaceChanged = true;                    if (update.state.surfaceVisible) {                        status = update.state.surfaceControl->hide();                        if (status) {                            ALOGE("Error %d hiding sprite surface after resize.", status);                        } else {                            update.state.surfaceVisible = false;                        }                    }                }            }        }    }    if (haveGlobalTransaction) {        SurfaceComposerClient::closeGlobalTransaction();    }

看到 update.state.surfaceControl = obtainSurface(update.state.surfaceWidth, update.state.surfaceHeight); 其实就是创建了一个surface,在一开始进入的主界面的时候,鼠标是没有的,当移动了下鼠标或者点击了下鼠标后就执行这个创建了这个surface

  • 黑屏分析

关于Android Graphic的渲染显示的总体流程就不细讲了,因为知识点太多无法展开

Android SurfaceFlinger与HWC的配合来实现硬鼠,也就是说鼠标不是用GPU画上去,而是由hwcomposer来处理的;当APP将rawdata放入GraphicBuffer后,SurfaceFlinger会询问hwcomposer(在prepare阶段实现),对于此Layer(Layer是跟Surface一一对应的)你hwcomposer处理不,若处理的话就将CompositionType置为OVERLAY(限于公司内部实现的hwcomposer,在此不贴源代码了),这样在SurfaceFlinger的doComposeSurface阶段就会将OVERLAY的Layer不再调用GPU去画了

bool SurfaceFlinger::doComposeSurfaces(const sp& hw, const Region& dirty){    RenderEngine& engine(getRenderEngine());    const int32_t id = hw->getHwcDisplayId();    HWComposer& hwc(getHwComposer());    HWComposer::LayerListIterator cur = hwc.begin(id);    const HWComposer::LayerListIterator end = hwc.end(id);    bool hasGlesComposition = hwc.hasGlesComposition(id);//当前的Display是否有GLES合成的Layer    if (hasGlesComposition) {        if (!hw->makeCurrent(mEGLDisplay, mEGLContext)) {            ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",                  hw->getDisplayName().string());            eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);            if(!getDefaultDisplayDevice()->makeCurrent(mEGLDisplay, mEGLContext)) {              ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");            }            return false;        }        // Never touch the framebuffer if we don't have any framebuffer layers        const bool hasHwcComposition = hwc.hasHwcComposition(id);        if (hasHwcComposition) {            // when using overlays, we assume a fully transparent framebuffer            // NOTE: we could reduce how much we need to clear, for instance            // remove where there are opaque FB layers. however, on some            // GPUs doing a "clean slate" clear might be more efficient.            // We'll revisit later if needed.            engine.clearWithColor(0, 0, 0, 0);//将back FrameBuffer全部清空        } else {            // we start with the whole screen area            const Region bounds(hw->getBounds());            // we remove the scissor part            // we're left with the letterbox region            // (common case is that letterbox ends-up being empty)            const Region letterbox(bounds.subtract(hw->getScissor()));            // compute the area to clear            Region region(hw->undefinedRegion.merge(letterbox));            // but limit it to the dirty region            region.andSelf(dirty);            // screen is already cleared here            if (!region.isEmpty()) {                // can happen with SurfaceView                drawWormhole(hw, region);//将back FrameBuffer对应的Region清空            }        }        if (hw->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {            // just to be on the safe side, we don't set the            // scissor on the main display. It should never be needed            // anyways (though in theory it could since the API allows it).            const Rect& bounds(hw->getBounds());            const Rect& scissor(hw->getScissor());            if (scissor != bounds) {                // scissor doesn't match the screen's dimensions, so we                // need to clear everything outside of it and enable                // the GL scissor so we don't draw anything where we shouldn't                // enable scissor for this frame                const uint32_t height = hw->getHeight();                engine.setScissor(scissor.left, height - scissor.bottom,                        scissor.getWidth(), scissor.getHeight());            }        }    }    /*     * and then, render the layers targeted at the framebuffer     */    const Vector< sp >& layers(hw->getVisibleLayersSortedByZ());    const size_t count = layers.size();    const Transform& tr = hw->getTransform();    if (cur != end) {        // we're using h/w composer        for (size_t i=0 ; i& layer(layers[i]);            const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));            if (!clip.isEmpty()) {                switch (cur->getCompositionType()) {                    case HWC_CURSOR_OVERLAY:                    case HWC_OVERLAY: {                        const Layer::State& state(layer->getDrawingState());                        if ((cur->getHints() & HWC_HINT_CLEAR_FB)                                && i                                && layer->isOpaque(state) && (state.alpha == 0xFF)                                && hasGlesComposition) {                            // never clear the very first layer since we're                            // guaranteed the FB is already cleared                            layer->clearWithOpenGL(hw);//GPU去画的时候,要将OVERLAY区域挖洞,以免将其遮挡,显示不出来                        }                        break;                    }                    case HWC_FRAMEBUFFER: {                        layer->draw(hw, clip);//GPU去画对应的Layer                        break;                    }                    case HWC_FRAMEBUFFER_TARGET: {//GPU最终渲染的目的地,可以理解为就是back FrameBuffer,保存合成后的结果的                        // this should not happen as the iterator shouldn't                        // let us get there.                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%zu)", i);                        break;                    }                }            }            layer->setAcquireFence(hw, *cur);        }    } else {        // we're not using h/w composer        for (size_t i=0 ; i& layer(layers[i]);            const Region clip(dirty.intersect(                    tr.transform(layer->visibleRegion)));            if (!clip.isEmpty()) {                layer->draw(hw, clip);            }        }    }    // disable scissor at the end of the frame    engine.disableScissor();    return true;}

走硬鼠时,dumpsys SurfaceFlinger信息如下

[20181213_15:30:57] h/w composer state:[20181213_15:30:57]   h/w composer present and enabled[20181213_15:30:57] Hardware Composer state (version 01010000):[20181213_15:30:57]   mDebugForceFakeVSync=0[20181213_15:30:57]   Display[0] configurations (* current):[20181213_15:30:57]     * 0: 1920x1080, xdpi=159.895004, ydpi=160.421005, refresh=16666666, colorMode=0[20181213_15:30:57]   numHwLayers=3, flags=00000000[20181213_15:30:57]     type   |  handle  | hint | flag | tr | blnd |   format    |     source crop (l,t,r,b)      |          frame         | name [20181213_15:30:57] -----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------[20181213_15:30:57]        HWC | ad808c40 | 0002 | 0000 | 00 | 0100 | RGBx_8888   |      0,      0,      1,      1 |    0,    0, 1920, 1080 | SurfaceView - com.mych.haixin.rude/com.mych.cloudgameclient.main.activity.StartUpActivity#0[20181213_15:30:57]        HWC | adb8f3c0 | 0000 | 0000 | 00 | 0105 | RGBA_8888   |      0,      0,     44,     56 |  375,  584,  419,  640 | Sprite#0[20181213_15:30:57]  FB TARGET | adeca6e0 | 0000 | 0000 | 00 | 0105 | RGBA_8888   |      0,      0,   1920,   1080 |    0,    0, 1920, 1080 | HWC_FRAMEBUFFER_TARGET

 可以看到此时参加Compose的Layer中并不存在需要GLES合成的Layer

那将我们添加的硬鼠逻辑去掉,让其走由GPU去画,这种情况下并没有黑帧遮住,其对应的dumpsys SurfaceFlinger信息如下

h/w composer state:  h/w composer present and enabledHardware Composer state (version 01010000):  mDebugForceFakeVSync=0  Display[0] configurations (* current):    * 0: 1920x1080, xdpi=159.895004, ydpi=160.421005, refresh=16666666, colorMode=0  numHwLayers=3, flags=00000000    type   |  handle  | hint | flag | tr | blnd |   format    |     source crop (l,t,r,b)      |          frame         | name -----------+----------+------+------+----+------+-------------+--------------------------------+------------------------+------       HWC | a80292c0 | 0002 | 0000 | 00 | 0100 | RGBx_8888   |      0,      0,      1,      1 |    0,    0, 1920, 1080 | SurfaceView - com.mych.haixin.rude/com.mych.cloudgameclient.main.activity.StartUpActivity#0      GLES | a80248c0 | 0000 | 0000 | 00 | 0105 | RGBA_8888   |      0,      0,     44,     56 |  388,  631,  432,  687 | Sprite#0 FB TARGET | a85c95a0 | 0000 | 0000 | 00 | 0105 | RGBA_8888   |      0,      0,   1920,   1080 |    0,    0, 1920, 1080 | HWC_FRAMEBUFFER_TARGET

这就比较奇怪了,不管走不走硬鼠,在这种case下都是只有两个Layer参与合成,那黑帧是哪个Layer造成的呢

而且在hwcomposer中将参与合成Layer的texture Buffer全部dump出来,也不存在黑帧,但dump出的FrameBufferTarget中是有黑帧的,这个黑帧其实是SurfaceView的Background-surfaceView,是本身就应该出现的,因为在SurfaceView的sidebandstream到来之前,需要拿黑屏遮一下,开始播放后,background-surfaceView就不会参与合成的

怀疑点1:是不是硬鼠条件下没有去清FrameBuffer,因为此时参与合成的Layer的compositionType都是OVERLAY,doComposeSurfaces中的hasGlesComposition为false,合成之前就不会去清FrameBuffer了,添加如下code,强制去清一次

    }else if (hasHwcComposition) {            // when using overlays, we assume a fully transparent framebuffer            // NOTE: we could reduce how much we need to clear, for instance            // remove where there are opaque FB layers. however, on some            // GPUs doing a "clean slate" clear might be more efficient.            // We'll revisit later if needed.            ALOGE("hasHwcComposition else if engine.clearWithColor(0, 0, 0, 0);");            engine.clearWithColor(0, 0, 0, 0);        }

测试结果是当硬鼠显示时依旧会有黑屏发生,发生的时长就是硬鼠存在的时间(因为鼠标不动的话,过一段时间会自动消失),硬鼠消失时,黑屏也消失了,透出了后面显示的内容。

奇怪了,不管当前的Layer是什么属性我都去清FrameBuffer了,黑帧出现了,我也已经清掉了啊,难道后面又画上去了,如果后面画上去的话,应该可以dump到这个黑帧

怀疑点2;是不是我虽然请了FrameBuffer(back FrameBuffer),但并没有执行swap,也就是说,你虽然清了,但显示时还是以前的Front FrameBuffer

void DisplayDevice::swapBuffers(HWComposer& hwc) const {#ifdef USE_HWC2    if (hwc.hasClientComposition(mHwcDisplayId)) {#else    // We need to call eglSwapBuffers() if:    //  (1) we don't have a hardware composer, or    //  (2) we did GLES composition this frame, and either    //    (a) we have framebuffer target support (not present on legacy    //        devices, where HWComposer::commit() handles things); or    //    (b) this is a virtual display    if (hwc.initCheck() != NO_ERROR ||            (hwc.hasGlesComposition(mHwcDisplayId) &&             (hwc.supportsFramebufferTarget() || mType >= DISPLAY_VIRTUAL))) {#endif        EGLBoolean success = eglSwapBuffers(mDisplay, mSurface);        ALOGE("eglSwapBuffers(%p, %p)",                        mDisplay, mSurface);        if (!success) {            EGLint error = eglGetError();            if (error == EGL_CONTEXT_LOST ||                    mType == DisplayDevice::DISPLAY_PRIMARY) {                LOG_ALWAYS_FATAL("eglSwapBuffers(%p, %p) failed with 0x%08x",                        mDisplay, mSurface, error);            } else {                ALOGE("eglSwapBuffers(%p, %p) failed with 0x%08x",                        mDisplay, mSurface, error);            }        }    }    status_t result = mDisplaySurface->advanceFrame();    if (result != NO_ERROR) {        ALOGE("[%s] failed pushing new frame to HWC: %d",                mDisplayName.string(), result);    }}

DisplayDevice调用eglswapBuffer的地方,有个条件判断

(hwc.hasGlesComposition(mHwcDisplayId),这个是false的,因为我们参与合成Layer中并没有GLES的Layer

将这个条件注释掉,测试发现黑屏的确不存在了,也就是说,当Layer中没有GPU(GLES)参与的条件下,没有执行swap去调用底层的OSD执行pandisplay去交换Front FrameBuffer。

那这种修改会不会有效率上的损失呢,按照SurfaceFlinger的设计,我只管GLES的合成,对HWC的CompositionType的去交给hwcomposer去控管,hwc又不能控制GPU去,让hwc去控制OSD去显示,虽然这样也可以做到,但不建议让hwc去通过driver直接去控,光时序问题就会将你整蒙的,在SurfaceFlinger中修改是最好的,因为大多数情况下SurfaceFlinger的每次合成都会去清FrameBuffer,在这种case下去清并swap并不会有performance上的损失的
另一种更简单的修改就是不要什么硬鼠了,其实鼠标那个小图标占不了多少GPU资源的(对于普通机型来说)

Android O中的hwc 1.1对于Cursor的支持不是很好,但这个在hwc 2.0中得到了解决,在hwc 2.0中直接给出了更新鼠标的接口(hwc2_function_pointer_t) set_cursor_position

结论:当compose的Surface(Layer)中没有Mali要参与的情况下,SurfaceFlinger和hwc都没有去清Framebuffer,但硬鼠的情况下,FrameBuffer显示了上次合成的结果,按照SurfaceFlinger的设计,这种情况我什么都不管了,全部交给hwc处理,但此时因为FrameBuffer并未clear,这样就导致残留和黑屏(其实是上一次的合成结果);这种情况可以在SurfaceFlinger中添加code,去清一下Framebuffer并swap Buffer。

更多相关文章

  1. Android(安卓)SplashActivity启动时黑屏的问题
  2. Android自学笔记(番外篇):全面搭建Linux环境(八)——AOSP参与者工作流
  3. Android(安卓)Activity之间跳转出现短暂黑屏的处理方法(转)
  4. Android避免启动时闪一下黑屏
  5. Android系统框架总结(好文)
  6. Android--ListView滑动时出现黑屏解决方法(整合)
  7. activity跳转闪现黑屏
  8. android activity FLAG_ACTIVITY_CLEAR_TASK 跳转出现短暂的白屏
  9. Android图形合成和显示系统---基于高通MSM8k MDP4平台

随机推荐

  1. Android(安卓)开发使用 Gradle 配置构建
  2. Java基础第一讲:Java的故事和Java编程环境
  3. [置顶] Android(安卓)从硬件到应用:一步一
  4. Android面试题目及其答案
  5. Android图像格式类及图像转换方法
  6. android 系统平台的架构
  7. android 各种控件颜色值的设置(使用Drawab
  8. Android框架简介
  9. Android消息通信之无所不能的第三方开源
  10. Android设计模式系列(6)--SDK源码之享元