Edge extension effect: shader reimplementation
X-axis activity transitions require the translation of the surfaces
involved. As this movement would create unwanted see-through, we would
have added side windows anchored to the moving activities, and textured
them by clamping their parents.
We are replacing the additional windows with the extension of the
surfaces, and filling the area without buffer with a shader.
See go/edge-extension-sksl for more info.
Bug: 322036393
Test: LayerSnapshotTest
Flag: EXEMPT (calls will be protected by wm shell with com.android.window.flags.edge_extension_shader)
Change-Id: I3682efd16a1b311d67a522bb85960f100948b2ea
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 70e3c64..e5f6b7b 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -322,6 +322,10 @@
<< touchableRegion.bottom << "," << touchableRegion.right << "}"
<< "}";
}
+
+ if (obj.edgeExtensionEffect.hasEffect()) {
+ out << obj.edgeExtensionEffect;
+ }
return out;
}
@@ -492,8 +496,10 @@
requested.what &
(layer_state_t::eBufferChanged | layer_state_t::eDataspaceChanged |
layer_state_t::eApiChanged | layer_state_t::eShadowRadiusChanged |
- layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged)) {
- forceClientComposition = shadowSettings.length > 0 || stretchEffect.hasEffect();
+ layer_state_t::eBlurRegionsChanged | layer_state_t::eStretchChanged |
+ layer_state_t::eEdgeExtensionChanged)) {
+ forceClientComposition = shadowSettings.length > 0 || stretchEffect.hasEffect() ||
+ edgeExtensionEffect.hasEffect();
}
if (forceUpdate ||
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 2b1b2c8..4e09381 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -367,6 +367,7 @@
snapshot.geomLayerBounds = getMaxDisplayBounds({});
snapshot.roundedCorner = RoundedCornerState();
snapshot.stretchEffect = {};
+ snapshot.edgeExtensionEffect = {};
snapshot.outputFilter.layerStack = ui::DEFAULT_LAYER_STACK;
snapshot.outputFilter.toInternalDisplay = false;
snapshot.isSecure = false;
@@ -811,6 +812,32 @@
: parentSnapshot.stretchEffect;
}
+ if (forceUpdate ||
+ (snapshot.clientChanges | parentSnapshot.clientChanges) &
+ layer_state_t::eEdgeExtensionChanged) {
+ if (requested.edgeExtensionParameters.extendLeft ||
+ requested.edgeExtensionParameters.extendRight ||
+ requested.edgeExtensionParameters.extendTop ||
+ requested.edgeExtensionParameters.extendBottom) {
+ // This is the root layer to which the extension is applied
+ snapshot.edgeExtensionEffect =
+ EdgeExtensionEffect(requested.edgeExtensionParameters.extendLeft,
+ requested.edgeExtensionParameters.extendRight,
+ requested.edgeExtensionParameters.extendTop,
+ requested.edgeExtensionParameters.extendBottom);
+ } else if (parentSnapshot.clientChanges & layer_state_t::eEdgeExtensionChanged) {
+ // Extension is inherited
+ snapshot.edgeExtensionEffect = parentSnapshot.edgeExtensionEffect;
+ } else {
+ // There is no edge extension
+ snapshot.edgeExtensionEffect.reset();
+ }
+ if (snapshot.edgeExtensionEffect.hasEffect()) {
+ snapshot.clientChanges |= layer_state_t::eEdgeExtensionChanged;
+ snapshot.changes |= RequestedLayerState::Changes::Geometry;
+ }
+ }
+
if (forceUpdate || snapshot.clientChanges & layer_state_t::eColorTransformChanged) {
if (!parentSnapshot.colorTransformIsIdentity) {
snapshot.colorTransform = parentSnapshot.colorTransform * requested.colorTransform;
@@ -899,6 +926,10 @@
updateLayerBounds(snapshot, requested, parentSnapshot, primaryDisplayRotationFlags);
}
+ if (snapshot.edgeExtensionEffect.hasEffect()) {
+ updateBoundsForEdgeExtension(snapshot);
+ }
+
if (forceUpdate || snapshot.clientChanges & layer_state_t::eCornerRadiusChanged ||
snapshot.changes.any(RequestedLayerState::Changes::Geometry |
RequestedLayerState::Changes::BufferUsageFlags)) {
@@ -917,8 +948,8 @@
}
// computed snapshot properties
- snapshot.forceClientComposition =
- snapshot.shadowSettings.length > 0 || snapshot.stretchEffect.hasEffect();
+ snapshot.forceClientComposition = snapshot.shadowSettings.length > 0 ||
+ snapshot.stretchEffect.hasEffect() || snapshot.edgeExtensionEffect.hasEffect();
snapshot.contentOpaque = snapshot.isContentOpaque();
snapshot.isOpaque = snapshot.contentOpaque && !snapshot.roundedCorner.hasRoundedCorners() &&
snapshot.color.a == 1.f;
@@ -973,6 +1004,31 @@
}
}
+/**
+ * According to the edges that we are requested to extend, we increase the bounds to the maximum
+ * extension allowed by the crop (parent crop + requested crop). The animation that called
+ * Transition#setEdgeExtensionEffect is in charge of setting the requested crop.
+ * @param snapshot
+ */
+void LayerSnapshotBuilder::updateBoundsForEdgeExtension(LayerSnapshot& snapshot) {
+ EdgeExtensionEffect& effect = snapshot.edgeExtensionEffect;
+
+ if (effect.extendsEdge(LEFT)) {
+ snapshot.geomLayerBounds.left = snapshot.geomLayerCrop.left;
+ }
+ if (effect.extendsEdge(RIGHT)) {
+ snapshot.geomLayerBounds.right = snapshot.geomLayerCrop.right;
+ }
+ if (effect.extendsEdge(TOP)) {
+ snapshot.geomLayerBounds.top = snapshot.geomLayerCrop.top;
+ }
+ if (effect.extendsEdge(BOTTOM)) {
+ snapshot.geomLayerBounds.bottom = snapshot.geomLayerCrop.bottom;
+ }
+
+ snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
+}
+
void LayerSnapshotBuilder::updateLayerBounds(LayerSnapshot& snapshot,
const RequestedLayerState& requested,
const LayerSnapshot& parentSnapshot,
@@ -1012,11 +1068,12 @@
FloatRect parentBounds = parentSnapshot.geomLayerBounds;
parentBounds = snapshot.localTransform.inverse().transform(parentBounds);
snapshot.geomLayerBounds =
- (requested.externalTexture) ? snapshot.bufferSize.toFloatRect() : parentBounds;
+ requested.externalTexture ? snapshot.bufferSize.toFloatRect() : parentBounds;
+ snapshot.geomLayerCrop = parentBounds;
if (!requested.crop.isEmpty()) {
- snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(requested.crop.toFloatRect());
+ snapshot.geomLayerCrop = snapshot.geomLayerCrop.intersect(requested.crop.toFloatRect());
}
- snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(parentBounds);
+ snapshot.geomLayerBounds = snapshot.geomLayerBounds.intersect(snapshot.geomLayerCrop);
snapshot.transformedBounds = snapshot.geomLayerTransform.transform(snapshot.geomLayerBounds);
const Rect geomLayerBoundsWithoutTransparentRegion =
RequestedLayerState::reduce(Rect(snapshot.geomLayerBounds),
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index dbbad76..f3c56a4 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -113,6 +113,10 @@
static void resetRelativeState(LayerSnapshot& snapshot);
static void updateRoundedCorner(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
const LayerSnapshot& parentSnapshot, const Args& args);
+ static bool extensionEdgeSharedWithParent(LayerSnapshot& snapshot,
+ const RequestedLayerState& requested,
+ const LayerSnapshot& parentSnapshot);
+ static void updateBoundsForEdgeExtension(LayerSnapshot& snapshot);
void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags);
static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested,
diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
index 17d3f4b..17d2610 100644
--- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
+++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp
@@ -609,8 +609,9 @@
layer_state_t::eSidebandStreamChanged | layer_state_t::eColorSpaceAgnosticChanged |
layer_state_t::eShadowRadiusChanged | layer_state_t::eFixedTransformHintChanged |
layer_state_t::eTrustedOverlayChanged | layer_state_t::eStretchChanged |
- layer_state_t::eBufferCropChanged | layer_state_t::eDestinationFrameChanged |
- layer_state_t::eDimmingEnabledChanged | layer_state_t::eExtendedRangeBrightnessChanged |
+ layer_state_t::eEdgeExtensionChanged | layer_state_t::eBufferCropChanged |
+ layer_state_t::eDestinationFrameChanged | layer_state_t::eDimmingEnabledChanged |
+ layer_state_t::eExtendedRangeBrightnessChanged |
layer_state_t::eDesiredHdrHeadroomChanged |
(FlagManager::getInstance().latch_unsignaled_with_auto_refresh_changed()
? layer_state_t::eFlagsChanged