Android显示系统——SurfaceFlinger之Layer Bounds计算方法
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);
}
}