关于android:Android-鼠标光标的图形合成

7次阅读

共计 14096 个字符,预计需要花费 36 分钟才能阅读完成。

始终很好奇鼠标光标是如何实现的,它反映很快、提早很小,没有受到 Android 显示零碎的影响。正好最近做相干的工作,跟着源码好好钻研一下。

本文参考 Android 9.0 源码。

从 Input 说起

咱们并不是要讲 Input,只想看看鼠标光标的绘制过程。然而,Android 将鼠标光标的实现放到了 Input 中,这看起来也是正当的。在 Input 中,光标由类Sprite 实现。源码中对 Sprite 的解释为:显示在其余图层之上的图形对象。看来 Sprite 并非专为光标设计,但在源码中的地位表明,它在 Android 中也只为鼠标或触摸之类的输出设施的光标服务。Sprite 的定义中也只提供了简略的图形操作。

frameworks/base/libs/input/SpriteController.h

/*
 * A sprite is a simple graphical object that is displayed on-screen above other layers.
 * The basic sprite class is an interface.
 * The implementation is provided by the sprite controller.
 */
class Sprite : public RefBase {
protected:
    Sprite() {}
    virtual ~Sprite() {}

public:
    enum {
        // The base layer for pointer sprites.
        BASE_LAYER_POINTER = 0, // reserve space for 1 pointer

        // The base layer for spot sprites.
        BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots
    };

    /* Sets the bitmap that is drawn by the sprite.
     * The sprite retains a copy of the bitmap for subsequent rendering. */
    virtual void setIcon(const SpriteIcon& icon) = 0;

    inline void clearIcon() {setIcon(SpriteIcon());
    }

    /* Sets whether the sprite is visible. */
    virtual void setVisible(bool visible) = 0;

    /* Sets the sprite position on screen, relative to the sprite's hot spot. */
    virtual void setPosition(float x, float y) = 0;

    /* Sets the layer of the sprite, relative to the system sprite overlay layer.
     * Layer 0 is the overlay layer, > 0 appear above this layer. */
    virtual void setLayer(int32_t layer) = 0;

    /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */
    virtual void setAlpha(float alpha) = 0;

    /* Sets the sprite transformation matrix. */
    virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
};

管制光标的类叫做 SpriteController,PointerController 会应用这个类来显示光标。这里咱们只关怀光标图形的合成,真正显示和更新光标的办法是 SpriteController::doUpdateSprites()

frameworks/base/libs/input/SpriteController.cpp

void SpriteController::doUpdateSprites() {
    // 从 invalidatedSprites 中收集须要更新的 Sprite
    Vector<SpriteUpdate> updates;
    size_t numSprites;
    { // acquire lock
        AutoMutex _l(mLock);

        numSprites = mLocked.invalidatedSprites.size();
        for (size_t i = 0; i < numSprites; i++) {const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i);

            updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
            sprite->resetDirtyLocked();}
        mLocked.invalidatedSprites.clear();} // release lock

    // surfaces 未创立或失落时,从新创立 surface
    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;
            // 创立 Surface,咱们这次的关注点
            update.state.surfaceControl = obtainSurface(update.state.surfaceWidth, update.state.surfaceHeight);
            if (update.state.surfaceControl != NULL) {update.surfaceChanged = surfaceChanged = true;}
        }
    }

    // 如果须要,从新调整 sprites 大小
    SurfaceComposerClient::Transaction t;
    bool needApplyTransaction = false;
    for (size_t i = 0; i < numSprites; i++) {
        ......
            if (update.state.surfaceWidth < desiredWidth
                    || update.state.surfaceHeight < desiredHeight) {
                needApplyTransaction = true;

                t.setSize(update.state.surfaceControl,
                        desiredWidth, desiredHeight);
                ......
            }
        }
    }
    if (needApplyTransaction) {t.apply();
    }

    // 如果须要,重画 sprites
    for (size_t i = 0; i < numSprites; i++) {SpriteUpdate& update = updates.editItemAt(i);

        if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
            update.state.surfaceDrawn = false;
            update.surfaceChanged = surfaceChanged = true;
        }

        if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
                && update.state.wantSurfaceVisible()) {sp<Surface> surface = update.state.surfaceControl->getSurface();
            ANativeWindow_Buffer outBuffer;
            ......
                // 应用 SKIA 画图
                SkBitmap surfaceBitmap;
                ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
                surfaceBitmap.installPixels(SkImageInfo::MakeN32Premul(outBuffer.width, outBuffer.height),
                                            outBuffer.bits, bpr);

                SkCanvas surfaceCanvas(surfaceBitmap);

                SkPaint paint;
                paint.setBlendMode(SkBlendMode::kSrc);
                surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint);

                if (outBuffer.width > update.state.icon.bitmap.width()) {paint.setColor(0); // transparent fill color
                    surfaceCanvas.drawRect(SkRect::MakeLTRB(update.state.icon.bitmap.width(), 0,
                            outBuffer.width, update.state.icon.bitmap.height()), paint);
                }
                if (outBuffer.height > update.state.icon.bitmap.height()) {paint.setColor(0); // transparent fill color
                    surfaceCanvas.drawRect(SkRect::MakeLTRB(0, update.state.icon.bitmap.height(),
                            outBuffer.width, outBuffer.height), paint);
                }
                ......
    }

    // 依据 dirty 值来设置 Surface
    needApplyTransaction = false;
    for (size_t i = 0; i < numSprites; i++) {SpriteUpdate& update = updates.editItemAt(i);

        bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
                && update.state.surfaceDrawn;
        bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
        bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
        if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
                || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
                        | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
                        | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {......}

    if (needApplyTransaction) {status_t status = t.apply();
        if (status) {ALOGE("Error applying Surface transaction");
        }
    }
......
}

一次的光标的更新就会波及到如此多的代码逻辑,可见 UI 真是不容易。其余的逻辑线不论,这次咱们只关怀光标的图层。上述代码通过 obtainSurface() 来创立 Surface。

frameworks/base/libs/input/SpriteController.cpp

sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {ensureSurfaceComposerClient();

    sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888,
            ISurfaceComposerClient::eHidden |
            ISurfaceComposerClient::eCursorWindow);
    if (surfaceControl == NULL || !surfaceControl->isValid()) {ALOGE("Error creating sprite surface.");
        return NULL;
    }
    return surfaceControl;
}

这里咱们须要重点关注的是 createSurface() 办法中的参数 flags。Sprite 中这个 flags 设置了 eHiddeneCursorWindow,它们表明创立的 Surface 是暗藏的,并标识为 Cursor 应用。

来到 Surface

Input 中为光标创立了一个 Surface,并且标识这是一个 Cursor 应用的 Surface。之后,Surface 中会依据情景对光标图层做非凡解决,这里的关键字就是 Cursor

咱们还是以光标图层为主线进行跟踪,先持续看下 createSurface()。通过一系列的 Binder 调用和 Message 传递,最终通过 SurfaceFlinger 的createLayer() 实现图层创立。

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
                                     uint32_t h, PixelFormat format, uint32_t flags,
                                     int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
                                     sp<IGraphicBufferProducer>* gbp,
                                     const sp<IBinder>& parentHandle,
                                     const sp<Layer>& parentLayer) {
    ......
    switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
        // 一般图层
        case ISurfaceComposerClient::eFXSurfaceNormal:
            result = createBufferLayer(client,
                    uniqueName, w, h, flags, format,
                    handle, gbp, &layer);

            break;
        // 纯色图层
        case ISurfaceComposerClient::eFXSurfaceColor:
            result = createColorLayer(client,
                    uniqueName, w, h, flags,
                    handle, &layer);
            break;
        default:
            result = BAD_VALUE;
            break;
    }
    ......
    // Client 中通过 Layer 治理 Surface,将创立的 Layer 退出到 LayerStack 中
    result = addClientLayer(client, *handle, *gbp, layer, parentHandle, parentLayer);
    if (result != NO_ERROR) {return result;}
    mInterceptor->saveSurfaceCreation(layer);

    setTransactionFlags(eTransactionNeeded);
    return result;
}

createLayer()中,光标算是一般图层,所以仅需调用 createBufferLayer() 来创立。

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
{
    ......
    // 创立一个 BufferLayer
    sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
    // 设置 Buffer 属性
    status_t err = layer->setBuffers(w, h, format, flags);
    if (err == NO_ERROR) {*handle = layer->getHandle(); // 获取 Layer 的句柄
        *gbp = layer->getProducer(); // 获取 GraphicBufferProducer 对象 
        *outLayer = layer;
    }

    ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
    return err;
}

其中 layer->setBuffers() 设置了该 BufferLayer 的属性。能够看到,当申请的是一个 Cursor 图层时,mPotentialCursor被设置为true,表明该 BufferLayer 作为 Cursor 应用。

frameworks/native/services/surfaceflinger/BufferLayer.cpp

status_t BufferLayer::setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
    ......
    mFormat = format;

    mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
    mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
    mCurrentOpacity = getOpacityForFormat(format);

    mConsumer->setDefaultBufferSize(w, h);
    mConsumer->setDefaultBufferFormat(format);
    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));

    return NO_ERROR;
}

SurfaceFlinger 中的 Cursor 操作

下面讲到 Cursor Layer 最外围的属性 mPotentialCursorcreateSurface() 只是设置了这个属性,真正的应用在 SurfaceFlinger 渲染过程中。接着我发现,想把这个货色看明确,先须要把 Android 图形合成弄清楚,这可是的宏大的工程。借张图,有趣味的本人钻研。

然而,工夫无限,怎么办?我的解决办法就是搜寻关键字。搜寻关键字 Cursor 后,能够失去一些相干的操作。SurfaceFlinger 接管到 Vsync 信号后,会调用 handleMessageRefresh() 来刷新显示。

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::handleMessageRefresh() {
    ......
    preComposition(refreshStartTime); // 合成预处理
    rebuildLayerStacks(); // 从新构建 LayerStacks
    setUpHWComposer(); // 更新 HWComposer 的图层和属性
    doDebugFlashRegions(); // 图形绘制的 debug 模式
    doTracing("handleRefresh");
    logLayerStats();
    doComposition(); // 合成所有图层
    postComposition(refreshStartTime); // 合成后处理
    ......
}

咱们还是只关怀 Cursor 的操作,它位于 HWComposer 管制的图层中。

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::setUpHWComposer() {
    ......
    // 遍历所有的 DisplayDevice,为绘制做筹备
    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
        ......
        mDisplays[dpy]->beginFrame(mustRecompose);

        if (mustRecompose) {mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
        }
    }

    // 设置 HWC Layer
    if (CC_UNLIKELY(mGeometryInvalid)) {
        mGeometryInvalid = false;
        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
            ......
                for (size_t i = 0; i < currentLayers.size(); i++) {const auto& layer = currentLayers[i];
                    // 尝试创立 HWC Layer,如果失败则强制 OpenGL 渲染
                    if (!layer->hasHwcLayer(hwcId)) {if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {layer->forceClientComposition(hwcId);
                            continue;
                        }
                    }

                    // 设置 HWC Layer 的显示区域、合成模式、Alpha、Order 等
                    layer->setGeometry(displayDevice, i);
                    // HWC 被禁止或绘制 debug 模式时,强制 OpenGL 渲染
                    if (mDebugDisableHWC || mDebugRegion) {layer->forceClientComposition(hwcId);
                    }
        ......
    }

    // 筹备 HWC 须要渲染的数据
    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {auto& displayDevice = mDisplays[displayId];
        const auto hwcId = displayDevice->getHwcDisplayId();
        ......
            // 调用 setPerFrameData 办法
            layer->setPerFrameData(displayDevice);
        ......
    }
    ......
    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
        ......
        // 尝试进行显示
        status_t result = displayDevice->prepareFrame(*getBE().mHwc);
        ......
    }
}

其中 setPerFrameData() 实现 HWComposer 的相干设置,为显示做筹备。

frameworks/native/services/surfaceflinger/BufferLayer.cpp

void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
    ......
    // 设置可见区域
    auto error = hwcLayer->setVisibleRegion(visible);
    ......
    // 设置刷新区域
    error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
    ......
    // Sideband layers 设置
    if (getBE().compositionInfo.hwc.sidebandStream.get()) {setCompositionType(hwcId, HWC2::Composition::Sideband);
        error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
        ......
        return;
    }

    if (mPotentialCursor) {
        // Cursor layers 设置
        setCompositionType(hwcId, HWC2::Composition::Cursor);
    } else {
        // Device layers 设置
        setCompositionType(hwcId, HWC2::Composition::Device);
    }

    // 设置色调空间
    error = hwcLayer->setDataspace(mCurrentDataSpace);
    if (error != HWC2::Error::None) {ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
              to_string(error).c_str(), static_cast<int32_t>(error));
    }

    // 获取 HDR 数据并设置到 HWC 中
    const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
    error = hwcLayer->setPerFrameMetadata(displayDevice->getSupportedPerFrameMetadata(), metadata);
    ......
    // 获取渲染的数据 buffer 和 Fence,设置到 HWC 中
    sp<GraphicBuffer> hwcBuffer;
    hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
                                     getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);

    auto acquireFence = mConsumer->getCurrentFence();
    error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
    ......
}

咱们终于找到了心愿看到的mPotentialCursor,通过这个标识通知 HWC2 这是一个 CursorLayer。除此之外,对于 CursorLayer 的操作与 DeviceLayer 并没有区别。所以,SurfaceFlinger 更多的是心愿 HWComposer 依据 Layer 的类型进行不同解决。目前 HWC2 反对的 Layer 类型有,

  1. HWC2_COMPOSITION_CLIENT:不通过 HWC 硬件来合成图层。GPU 将这类图层合成到一个图像 Buffer 中,而后传递给 HWC。
  2. HWC2_COMPOSITION_DEVICE:应用 HWC 硬件来合成图层。
  3. HWC2_COMPOSITION_SOLID_COLOR:用来解决 ColorLayer 数据,如果 HWC 不反对,则改为应用 CLIENT 形式合成。
  4. HWC2_COMPOSITION_CURSOR:用来解决 CursorLayer 数据,地位通过setCursorPosition 异步设置。如果 HWC 不反对,则改为应用 CLIENT 或 DEVICE 形式合成。
  5. HWC2_COMPOSITION_SIDEBAND:对于这种 Layer,须要由内部机制提供内容更新,例如电视信号的视频数据。如果 HWC 不反对,则改为应用 CLIENT 或 DEVICE 形式合成,但可能无奈正确显示。

Cursor Layer 还有一个重要的操作,setCursorPosition(),这个办法用来设置 Cursor 的地位,具体的实现仍然在 HWComposer 中。当用户过程更新 Surface 图形时,SurfaceFlinger 会发送 INVALIDATE 音讯给相应的 Layer。音讯解决函数调用 handleTransaction()handlePageFlip()来更新 Layer 对象。handleTransaction()

用来解决 Layer 和显示设施的变动,它持续调用handleTransactionLocked()

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
    ......
    // 解决 Layer 的变动
    if (transactionFlags & eTraversalNeeded) {......}

    // 解决显示设施的变动
    if (transactionFlags & eDisplayTransactionNeeded) {processDisplayChangesLocked();
        processDisplayHotplugEventsLocked();}

    // 设置 transform hint
    if (transactionFlags & (eDisplayLayerStackChanged|eDisplayTransactionNeeded)) {......}

   // 解决 Layer 的增减
   if (mLayersAdded) {......}

    if (mLayersRemoved) {......}

    commitTransaction();

    // 更新光标地位
    updateCursorAsync();}

咱们找到了 Cursor 更新的中央,SurfaceFlinger 更新图形时会同步更新光标地位。之后,在 Vsync 到来时,实现图像的更新显示。

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp

void SurfaceFlinger::updateCursorAsync()
{for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
        ......
        // 调用 Layer 的对应办法
        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {layer->updateCursorPosition(displayDevice);
        }
    }
}
frameworks/native/services/surfaceflinger/Layer.cpp

void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) {
    // HWC Layer 不存在或者不是 Cursor Layer,不做解决
    auto hwcId = displayDevice->getHwcDisplayId();
    if (getBE().mHwcLayers.count(hwcId) == 0 ||
        getCompositionType(hwcId) != HWC2::Composition::Cursor) {return;}
    ......
    // 获取图层的地位
    Rect bounds = reduce(win, s.activeTransparentRegion);
    Rect frame(getTransform().transform(bounds));
    frame.intersect(displayDevice->getViewport(), &frame);
    if (!s.finalCrop.isEmpty()) {frame.intersect(s.finalCrop, &frame);
    }
    auto& displayTransform(displayDevice->getTransform());
    auto position = displayTransform.transform(frame);

    // 调用 HWC 的办法来设置图层地位
    auto error = getBE().mHwcLayers[hwcId].layer->setCursorPosition(position.left, position.top);
}

达到 HWComposer

下面剖析了许多代码,但真正与 Cursor 相干的并不多。CursorLayer 的真正实现还是在 HWComposer 中。然而 HWComposer 的实现是与平台相干的,不同的平台对 CursorLayer 的实现可能不同。效率的形式是应用一个独立的硬件 OSD 来显示 CursorLayer,而后通过硬件合成的形式将 CursorLayer 叠加到 UI 显示层。应用这种形式,光标的挪动效率也很高,只有扭转硬件 OSD 显示的地位即可。如果没有独立的硬件 OSD 来应用,就只能在规范显示层上进行软件叠加,或者应用 GPU 来叠加。

因为跟平台相干的实现具备私密性,这里不再持续剖析。

参考文档:

Android GUI 零碎之 SurfaceFlinger)

Android SurfaceFlinger 学习 -HWComposer Composition 工作流程

挪动端显示技术杂谈

正文完
 0