Android显示系统——SurfaceFlinger之Layer Bounds计算方法

发布时间 2023-07-05 22:35:55作者: TPrime.A

Layer Bounds计算过程分析

从SurfaceFlinger的这里看起:

void SurfaceFlinger::computeLayerBounds() {
    const FloatRect maxBounds = getMaxDisplayBounds();
    for (const auto& layer : mDrawingState.layersSortedByZ) {
        layer->computeBounds(maxBounds, ui::Transform(), 0.f /* shadowRadius */);
    }
}

首先,通过getMaxDisplayBounds()获取屏幕最大边缘:

FloatRect SurfaceFlinger::getMaxDisplayBounds() {
    const ui::Size maxSize = [this] {
        ftl::FakeGuard guard(mStateLock);
        if (mDisplays.empty()) return ui::Size{5000, 5000};  // 如果是无屏设备上面,最大支持5000x5000的大小

        // 返回mDisplays中最大屏幕尺寸
        return std::accumulate(mDisplays.begin(), mDisplays.end(), ui::kEmptySize,
                               [](ui::Size size, const auto& pair) -> ui::Size {
                                   const auto& display = pair.second;
                                   return {std::max(size.getWidth(), display->getWidth()),
                                           std::max(size.getHeight(), display->getHeight())};
                               });
    }();

    // 这里直接将上面的最大屏幕尺寸扩大了10倍,相当于上面的计算直接被忽略了,因为后面会重新进行计算。
    const float xMax = maxSize.getWidth() * 10.f;
    const float yMax = maxSize.getHeight() * 10.f;

    return {-xMax, -yMax, xMax, yMax};
}

再回到SurfaceFlinger::computeLayerBounds()函数,接着对mDrawingState中按z值排序的所有layer进行循环遍历,分别计算其Bround大小。
这里面传了三个入参,一个是前面获取到的最大屏幕尺寸的10倍大小,一个被默认初始的ui::Transform,默认值为0的parentShadowRadius。

void Layer::computeBounds(FloatRect parentBounds, // 默认最大屏幕分辨率大小的10倍大小
                          ui::Transform parentTransform, // ui::Transform的初始默认值,无任何转换
                          float parentShadowRadius) {  // 默认值,0
    const State& s(getDrawingState());

    // 根据父layer的transform计算当前layer的transform,mEffectiveTransform用于将当前layer空间坐标转换成Screen空间坐标,这一变换包含了平衡和缩放
    mEffectiveTransform = parentTransform * getActiveTransform(s);

    if (CC_UNLIKELY(!isTransformValid())) {
        ALOGW("Stop computing bounds for %s because it has invalid transformation.",
              getDebugName());
        return;
    }

    // 先取当前layer的transform,对其取逆矩阵,然后对parentBounds做变换运算,将父图层的bounds变换到layer空间
    parentBounds = getActiveTransform(s).inverse().transform(parentBounds);

    // 计算源内容的bounds,如果没有定义bounds,则返回buffer的size。如果没有buffer,则返回父layer的bounds,对于根节点图层,则返回display的viewport大小,一般情况下默认为全屏大小
    mSourceBounds = computeSourceBounds(parentBounds);

    // Calculate bounds by croping diplay frame with layer crop and parent bounds
    FloatRect bounds = mSourceBounds;
    const Rect layerCrop = getCrop(s);  // 获取layer::State中的crop(基于layer space坐标定义)
    if (!layerCrop.isEmpty()) {
        // 计算mSourceBounds与layerCrop的重叠区域,取最终重叠区域的rect
        bounds = mSourceBounds.intersect(layerCrop.toFloatRect());
    }
    // 将bounds的区域与父图层再次计算重叠区域
    bounds = bounds.intersect(parentBounds);

    mBounds = bounds; // 最新计算出layer的区域mBounds
    // 通过mEffectiveTransform将layer的mBounds转换成屏幕上的区域mScreenBounds
    mScreenBounds = mEffectiveTransform.transform(mBounds);

    // 判断当前layer的shadow半径大小,若没指定,则使用父图层的shadow半径
    if (s.shadowRadius > 0.f) {
        mEffectiveShadowRadius = s.shadowRadius;
    } else {
        mEffectiveShadowRadius = parentShadowRadius;
    }

    // 这里强制指定shadowRadius只能向下传递一层
    // 若当前图层指定了shadowRadius则能绘制shadow,则不需要子图层继承当前图层的shadowRadius,即子图层可以绘制自己的shadow,而不需要管父图层的shadow诉求
    // 若当前图层指定了shadowRadius(可能为0)但无法绘制shader,则交由其子图层绘制shadow(子图层的shadow大小可以自定义,也可以继承当前图层),即子图层需要处理父图层未完成的shadow绘制操作
    const float childShadowRadius = canDrawShadows() ? 0.f : mEffectiveShadowRadius;

    for (const sp<Layer>& child : mDrawingChildren) {
        child->computeBounds(mBounds, mEffectiveTransform, childShadowRadius);
    }
}