SF: Split FE and CE

Make LayerFE a standalone class with no links back to Layer. Pass
LayerSnapshot from Layer into LayerFE before CompositionEngine::present
and back after.

Bug: 238781169
Test: go/wm-smoke
Test: presubmit

Change-Id: I5395fb717a931f88e2bf26395acd21e8b308961e
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 8a76d7c..67a226e 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -163,6 +163,7 @@
         "HwcSlotGenerator.cpp",
         "WindowInfosListenerInvoker.cpp",
         "Layer.cpp",
+        "LayerFE.cpp",
         "LayerProtoHelper.cpp",
         "LayerRenderArea.cpp",
         "LayerVector.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index fe8cad5..608c53a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -118,6 +118,9 @@
 
         // Requested white point of the layer in nits
         const float whitePointNits;
+
+        // True if layers with 170M dataspace should be overridden to sRGB.
+        const bool treat170mAsSrgb;
     };
 
     // A superset of LayerSettings required by RenderEngine to compose a layer
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
index 5aec7c2..e309442 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/planner/LayerState.h
@@ -72,6 +72,7 @@
     SolidColor            = 1u << 16,
     BackgroundBlurRadius  = 1u << 17,
     BlurRegions           = 1u << 18,
+    HasProtectedContent   = 1u << 19,
 };
 // clang-format on
 
@@ -245,9 +246,9 @@
 
     ui::Dataspace getDataspace() const { return mOutputDataspace.get(); }
 
-    bool isProtected() const {
-        return getOutputLayer()->getLayerFE().getCompositionState()->hasProtectedContent;
-    }
+    wp<GraphicBuffer> getBuffer() const { return mBuffer.get(); }
+
+    bool isProtected() const { return mIsProtected.get(); }
 
     bool hasSolidColorCompositionType() const {
         return getOutputLayer()->getLayerFE().getCompositionState()->compositionType ==
@@ -482,7 +483,11 @@
                                       return hash;
                                   }};
 
-    static const constexpr size_t kNumNonUniqueFields = 17;
+    OutputLayerState<bool, LayerStateField::HasProtectedContent> mIsProtected{[](auto layer) {
+        return layer->getLayerFE().getCompositionState()->hasProtectedContent;
+    }};
+
+    static const constexpr size_t kNumNonUniqueFields = 18;
 
     std::array<StateInterface*, kNumNonUniqueFields> getNonUniqueFields() {
         std::array<const StateInterface*, kNumNonUniqueFields> constFields =
@@ -501,7 +506,7 @@
                 &mAlpha,        &mLayerMetadata,  &mVisibleRegion,        &mOutputDataspace,
                 &mPixelFormat,  &mColorTransform, &mCompositionType,      &mSidebandStream,
                 &mBuffer,       &mSolidColor,     &mBackgroundBlurRadius, &mBlurRegions,
-                &mFrameNumber,
+                &mFrameNumber,  &mIsProtected,
         };
     }
 };
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e3f3680..0622534 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -900,6 +900,13 @@
     ui::Dataspace bestDataSpace = ui::Dataspace::V0_SRGB;
     *outHdrDataSpace = ui::Dataspace::UNKNOWN;
 
+    // An Output's layers may be stale when it is disabled. As a consequence, the layers returned by
+    // getOutputLayersOrderedByZ may not be in a valid state and it is not safe to access their
+    // properties. Return a default dataspace value in this case.
+    if (!getState().isEnabled) {
+        return ui::Dataspace::V0_SRGB;
+    }
+
     for (const auto* layer : getOutputLayersOrderedByZ()) {
         switch (layer->getLayerFE().getCompositionState()->dataspace) {
             case ui::Dataspace::V0_SCRGB:
@@ -1420,7 +1427,8 @@
                                        .realContentIsVisible = realContentIsVisible,
                                        .clearContent = !clientComposition,
                                        .blurSetting = blurSetting,
-                                       .whitePointNits = layerState.whitePointNits};
+                                       .whitePointNits = layerState.whitePointNits,
+                                       .treat170mAsSrgb = outputState.treat170mAsSrgb};
                 if (auto clientCompositionSettings =
                             layerFE.prepareClientComposition(targetSettings)) {
                     clientCompositionLayers.push_back(std::move(*clientCompositionSettings));
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
index 0731d48..ed9a88d 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/CachedSet.cpp
@@ -411,8 +411,8 @@
 
     if (mLayers.size() == 1) {
         base::StringAppendF(&result, "    Layer [%s]\n", mLayers[0].getName().c_str());
-        if (auto* buffer = mLayers[0].getBuffer().get()) {
-            base::StringAppendF(&result, "    Buffer %p", buffer);
+        if (const sp<GraphicBuffer> buffer = mLayers[0].getState()->getBuffer().promote()) {
+            base::StringAppendF(&result, "    Buffer %p", buffer.get());
             base::StringAppendF(&result, "    Format %s",
                                 decodePixelFormat(buffer->getPixelFormat()).c_str());
         }
@@ -422,8 +422,8 @@
         result.append("    Cached set of:\n");
         for (const Layer& layer : mLayers) {
             base::StringAppendF(&result, "      Layer [%s]\n", layer.getName().c_str());
-            if (auto* buffer = layer.getBuffer().get()) {
-                base::StringAppendF(&result, "       Buffer %p", buffer);
+            if (const sp<GraphicBuffer> buffer = layer.getState()->getBuffer().promote()) {
+                base::StringAppendF(&result, "       Buffer %p", buffer.get());
                 base::StringAppendF(&result, "    Format[%s]",
                                     decodePixelFormat(buffer->getPixelFormat()).c_str());
             }
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index eb209e9..514a8ff 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -2081,6 +2081,7 @@
         mOutput.setDisplayColorProfileForTest(
                 std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
         mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+        mOutput.editState().isEnabled = true;
 
         EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0))
                 .WillRepeatedly(Return(&mLayer1.mOutputLayer));
@@ -4464,6 +4465,7 @@
             true /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4476,6 +4478,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     LayerFE::LayerSettings mBlackoutSettings = mLayers[1].mLayerSettings;
@@ -4516,6 +4519,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(Rect(0, 0, 30, 30)),
@@ -4528,6 +4532,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(Rect(0, 0, 40, 201)),
@@ -4540,6 +4545,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
@@ -4570,6 +4576,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4582,6 +4589,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4594,6 +4602,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
@@ -4624,6 +4633,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4636,6 +4646,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4648,6 +4659,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
@@ -4677,6 +4689,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4689,6 +4702,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4701,6 +4715,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
@@ -4728,6 +4743,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer1TargetSettings{
             Region(kDisplayFrame),
@@ -4740,6 +4756,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
     compositionengine::LayerFE::ClientCompositionTargetSettings layer2TargetSettings{
             Region(kDisplayFrame),
@@ -4752,6 +4769,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(*mLayers[0].mLayerFE, prepareClientComposition(Eq(ByRef(layer0TargetSettings))))
@@ -4936,6 +4954,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(leftLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
@@ -4954,6 +4973,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(rightLayer.mOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
@@ -4987,6 +5007,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     LayerFE::LayerSettings mShadowSettings;
@@ -5029,6 +5050,7 @@
             false /* clearContent */,
             compositionengine::LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled,
             kLayerWhitePointNits,
+            false /* treat170mAsSrgb */,
     };
 
     EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9bb9305..c2a0e30 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -40,7 +40,6 @@
 #include <ftl/enum.h>
 #include <ftl/fake_guard.h>
 #include <gui/BufferItem.h>
-#include <gui/GLConsumer.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 #include <gui/TraceUtils.h>
@@ -81,28 +80,8 @@
 namespace {
 constexpr int kDumpTableRowLength = 159;
 
-static constexpr float defaultMaxLuminance = 1000.0;
-
 const ui::Transform kIdentityTransform;
 
-constexpr mat4 inverseOrientation(uint32_t transform) {
-    const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
-    const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
-    const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
-    mat4 tr;
-
-    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        tr = tr * rot90;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        tr = tr * flipH;
-    }
-    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        tr = tr * flipV;
-    }
-    return inverse(tr);
-}
-
 bool assignTransform(ui::Transform* dst, ui::Transform& from) {
     if (*dst == from) {
         return false;
@@ -164,7 +143,8 @@
         mLayerCreationFlags(args.flags),
         mBorderEnabled(false),
         mTextureName(args.textureName),
-        mHwcSlotGenerator(sp<HwcSlotGenerator>::make()) {
+        mHwcSlotGenerator(sp<HwcSlotGenerator>::make()),
+        mLayerFE(args.flinger->getFactory().createLayerFE(mName)) {
     ALOGV("Creating Layer %s", getDebugName());
 
     uint32_t layerFlags = 0;
@@ -652,12 +632,6 @@
     snapshot->cursorFrame = frame;
 }
 
-sp<compositionengine::LayerFE> Layer::asLayerFE() const {
-    compositionengine::LayerFE* layerFE = const_cast<compositionengine::LayerFE*>(
-            static_cast<const compositionengine::LayerFE*>(this));
-    return sp<compositionengine::LayerFE>::fromExisting(layerFE);
-}
-
 const char* Layer::getDebugName() const {
     return mName.c_str();
 }
@@ -666,237 +640,6 @@
 // drawing...
 // ---------------------------------------------------------------------------
 
-std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientComposition(
-        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
-    std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
-            prepareClientCompositionInternal(targetSettings);
-    // Nothing to render.
-    if (!layerSettings) {
-        return {};
-    }
-
-    // HWC requests to clear this layer.
-    if (targetSettings.clearContent) {
-        prepareClearClientComposition(*layerSettings, false /* blackout */);
-        return layerSettings;
-    }
-
-    // set the shadow for the layer if needed
-    prepareShadowClientComposition(*layerSettings, targetSettings.viewport);
-
-    return layerSettings;
-}
-
-std::optional<compositionengine::LayerFE::LayerSettings> Layer::prepareClientCompositionInternal(
-        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
-    ATRACE_CALL();
-
-    const auto* snapshot = getLayerSnapshot();
-    if (!snapshot) {
-        return {};
-    }
-
-    compositionengine::LayerFE::LayerSettings layerSettings;
-    layerSettings.geometry.boundaries =
-            reduce(snapshot->geomLayerBounds, snapshot->transparentRegionHint);
-    layerSettings.geometry.positionTransform = snapshot->geomLayerTransform.asMatrix4();
-
-    // skip drawing content if the targetSettings indicate the content will be occluded
-    const bool drawContent = targetSettings.realContentIsVisible || targetSettings.clearContent;
-    layerSettings.skipContentDraw = !drawContent;
-
-    if (hasColorTransform()) {
-        layerSettings.colorTransform = snapshot->colorTransform;
-    }
-
-    const auto& roundedCornerState = snapshot->roundedCorner;
-    layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius;
-    layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect;
-
-    layerSettings.alpha = snapshot->alpha;
-    layerSettings.sourceDataspace = snapshot->dataspace;
-
-    // Override the dataspace transfer from 170M to sRGB if the device configuration requests this.
-    // We do this here instead of in buffer info so that dumpsys can still report layers that are
-    // using the 170M transfer.
-    if (mFlinger->mTreat170mAsSrgb &&
-        (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) ==
-                HAL_DATASPACE_TRANSFER_SMPTE_170M) {
-        layerSettings.sourceDataspace = static_cast<ui::Dataspace>(
-                (layerSettings.sourceDataspace & HAL_DATASPACE_STANDARD_MASK) |
-                (layerSettings.sourceDataspace & HAL_DATASPACE_RANGE_MASK) |
-                HAL_DATASPACE_TRANSFER_SRGB);
-    }
-
-    layerSettings.whitePointNits = targetSettings.whitePointNits;
-    switch (targetSettings.blurSetting) {
-        case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled:
-            layerSettings.backgroundBlurRadius = snapshot->backgroundBlurRadius;
-            layerSettings.blurRegions = snapshot->blurRegions;
-            layerSettings.blurRegionTransform = snapshot->geomInverseLayerTransform.asMatrix4();
-            break;
-        case LayerFE::ClientCompositionTargetSettings::BlurSetting::BackgroundBlurOnly:
-            layerSettings.backgroundBlurRadius = snapshot->backgroundBlurRadius;
-            break;
-        case LayerFE::ClientCompositionTargetSettings::BlurSetting::BlurRegionsOnly:
-            layerSettings.blurRegions = snapshot->blurRegions;
-            layerSettings.blurRegionTransform = snapshot->geomInverseLayerTransform.asMatrix4();
-            break;
-        case LayerFE::ClientCompositionTargetSettings::BlurSetting::Disabled:
-        default:
-            break;
-    }
-    layerSettings.stretchEffect = snapshot->stretchEffect;
-    // Record the name of the layer for debugging further down the stack.
-    layerSettings.name = snapshot->name;
-
-    if (hasEffect() && !hasBufferOrSidebandStream()) {
-        prepareEffectsClientComposition(layerSettings, targetSettings);
-        return layerSettings;
-    }
-
-    prepareBufferStateClientComposition(layerSettings, targetSettings);
-    return layerSettings;
-}
-
-void Layer::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings,
-                                          bool blackout) const {
-    layerSettings.source.buffer.buffer = nullptr;
-    layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
-    layerSettings.disableBlending = true;
-    layerSettings.bufferId = 0;
-    layerSettings.frameNumber = 0;
-
-    // If layer is blacked out, force alpha to 1 so that we draw a black color layer.
-    layerSettings.alpha = blackout ? 1.0f : 0.0f;
-    layerSettings.name = getLayerSnapshot()->name;
-}
-
-void Layer::prepareEffectsClientComposition(
-        compositionengine::LayerFE::LayerSettings& layerSettings,
-        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
-    // If fill bounds are occluded or the fill color is invalid skip the fill settings.
-    if (targetSettings.realContentIsVisible && fillsColor()) {
-        // Set color for color fill settings.
-        layerSettings.source.solidColor = getColor().rgb;
-    } else if (hasBlur() || drawShadows()) {
-        layerSettings.skipContentDraw = true;
-    }
-}
-
-void Layer::prepareBufferStateClientComposition(
-        compositionengine::LayerFE::LayerSettings& layerSettings,
-        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
-    ATRACE_CALL();
-    const auto* snapshot = getLayerSnapshot();
-    if (CC_UNLIKELY(!snapshot->externalTexture)) {
-        // If there is no buffer for the layer or we have sidebandstream where there is no
-        // activeBuffer, then we need to return LayerSettings.
-        return;
-    }
-    const bool blackOutLayer =
-            (snapshot->hasProtectedContent && !targetSettings.supportsProtectedContent) ||
-            ((snapshot->isSecure || snapshot->hasProtectedContent) && !targetSettings.isSecure);
-    const bool bufferCanBeUsedAsHwTexture =
-            snapshot->externalTexture->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
-    if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
-        ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
-                 snapshot->name.c_str());
-        prepareClearClientComposition(layerSettings, true /* blackout */);
-        return;
-    }
-
-    layerSettings.source.buffer.buffer = snapshot->externalTexture;
-    layerSettings.source.buffer.isOpaque = snapshot->contentOpaque;
-    layerSettings.source.buffer.fence = snapshot->acquireFence;
-    layerSettings.source.buffer.textureName = snapshot->textureName;
-    layerSettings.source.buffer.usePremultipliedAlpha = snapshot->premultipliedAlpha;
-    layerSettings.source.buffer.isY410BT2020 = snapshot->isHdrY410;
-    bool hasSmpte2086 = snapshot->hdrMetadata.validTypes & HdrMetadata::SMPTE2086;
-    bool hasCta861_3 = snapshot->hdrMetadata.validTypes & HdrMetadata::CTA861_3;
-    float maxLuminance = 0.f;
-    if (hasSmpte2086 && hasCta861_3) {
-        maxLuminance = std::min(snapshot->hdrMetadata.smpte2086.maxLuminance,
-                                snapshot->hdrMetadata.cta8613.maxContentLightLevel);
-    } else if (hasSmpte2086) {
-        maxLuminance = snapshot->hdrMetadata.smpte2086.maxLuminance;
-    } else if (hasCta861_3) {
-        maxLuminance = snapshot->hdrMetadata.cta8613.maxContentLightLevel;
-    } else {
-        switch (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) {
-            case HAL_DATASPACE_TRANSFER_ST2084:
-            case HAL_DATASPACE_TRANSFER_HLG:
-                // Behavior-match previous releases for HDR content
-                maxLuminance = defaultMaxLuminance;
-                break;
-        }
-    }
-    layerSettings.source.buffer.maxLuminanceNits = maxLuminance;
-    layerSettings.frameNumber = snapshot->frameNumber;
-    layerSettings.bufferId = snapshot->externalTexture->getId();
-
-    const bool useFiltering = targetSettings.needsFiltering ||
-            snapshot->geomLayerTransform.needsBilinearFiltering() || snapshot->bufferNeedsFiltering;
-
-    // Query the texture matrix given our current filtering mode.
-    float textureMatrix[16];
-    getDrawingTransformMatrix(useFiltering, textureMatrix);
-
-    if (snapshot->geomBufferUsesDisplayInverseTransform) {
-        /*
-         * the code below applies the primary display's inverse transform to
-         * the texture transform
-         */
-        uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
-        mat4 tr = inverseOrientation(transform);
-
-        /**
-         * TODO(b/36727915): This is basically a hack.
-         *
-         * Ensure that regardless of the parent transformation,
-         * this buffer is always transformed from native display
-         * orientation to display orientation. For example, in the case
-         * of a camera where the buffer remains in native orientation,
-         * we want the pixels to always be upright.
-         */
-        const auto parentTransform = snapshot->transform;
-        tr = tr * inverseOrientation(parentTransform.getOrientation());
-
-        // and finally apply it to the original texture matrix
-        const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
-        memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
-    }
-
-    const Rect win{layerSettings.geometry.boundaries};
-    float bufferWidth = snapshot->bufferSize.getWidth();
-    float bufferHeight = snapshot->bufferSize.getHeight();
-
-    // Layers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
-    // been set and there is no parent layer bounds. In that case, the scale is meaningless so
-    // ignore them.
-    if (!snapshot->bufferSize.isValid()) {
-        bufferWidth = float(win.right) - float(win.left);
-        bufferHeight = float(win.bottom) - float(win.top);
-    }
-
-    const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
-    const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
-    const float translateY = float(win.top) / bufferHeight;
-    const float translateX = float(win.left) / bufferWidth;
-
-    // Flip y-coordinates because GLConsumer expects OpenGL convention.
-    mat4 tr = mat4::translate(vec4(.5f, .5f, 0.f, 1.f)) * mat4::scale(vec4(1.f, -1.f, 1.f, 1.f)) *
-            mat4::translate(vec4(-.5f, -.5f, 0.f, 1.f)) *
-            mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) *
-            mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f));
-
-    layerSettings.source.buffer.useTextureFiltering = useFiltering;
-    layerSettings.source.buffer.textureTransform =
-            mat4(static_cast<const float*>(textureMatrix)) * tr;
-
-    return;
-}
-
 aidl::android::hardware::graphics::composer3::Composition Layer::getCompositionType(
         const DisplayDevice& display) const {
     const auto outputLayer = findOutputLayerForDisplay(&display);
@@ -1816,6 +1559,8 @@
                 newParent->canDrawShadows() ? 0.f : newParent->mEffectiveShadowRadius;
         child->computeBounds(newParent->mBounds, newParent->mEffectiveTransform,
                              parentShadowRadius);
+        child->updateSnapshot(true /* updateGeometry */);
+        child->updateChildrenSnapshots(true /* updateGeometry */);
     }
 }
 
@@ -2139,7 +1884,7 @@
     return regionsCopy;
 }
 
-Layer::RoundedCornerState Layer::getRoundedCornerState() const {
+RoundedCornerState Layer::getRoundedCornerState() const {
     // Get parent settings
     RoundedCornerState parentSettings;
     const auto& parent = mDrawingParent.promote();
@@ -2180,21 +1925,6 @@
     return {};
 }
 
-void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster,
-                                           const Rect& layerStackRect) const {
-    const auto* snapshot = getLayerSnapshot();
-    renderengine::ShadowSettings state = snapshot->shadowSettings;
-    if (state.length <= 0.f || (state.ambientColor.a <= 0.f && state.spotColor.a <= 0.f)) {
-        return;
-    }
-
-    // Shift the spot light x-position to the middle of the display and then
-    // offset it by casting layer's screen pos.
-    state.lightPos.x = (layerStackRect.width() / 2.f) - snapshot->transformedBounds.left;
-    state.lightPos.y -= snapshot->transformedBounds.top;
-    caster.shadow = state;
-}
-
 bool Layer::findInHierarchy(const sp<Layer>& l) {
     if (l == this) {
         return true;
@@ -3377,7 +3107,7 @@
     return fenceSignaled;
 }
 
-bool Layer::onPreComposition(nsecs_t refreshStartTime, bool /* updatingOutputGeometryThisFrame */) {
+bool Layer::onPreComposition(nsecs_t refreshStartTime) {
     for (const auto& handle : mDrawingState.callbackHandles) {
         handle->refreshStartTime = refreshStartTime;
     }
@@ -3788,26 +3518,31 @@
             mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102);
 }
 
-sp<compositionengine::LayerFE> Layer::getCompositionEngineLayerFE() const {
+sp<LayerFE> Layer::getCompositionEngineLayerFE() const {
     // There's no need to get a CE Layer if the layer isn't going to draw anything.
-    if (hasSomethingToDraw()) {
-        return asLayerFE();
-    } else {
-        return nullptr;
-    }
+    return hasSomethingToDraw() ? mLayerFE : nullptr;
 }
 
-const Layer::LayerSnapshot* Layer::getLayerSnapshot() const {
+const LayerSnapshot* Layer::getLayerSnapshot() const {
     return mSnapshot.get();
 }
 
-Layer::LayerSnapshot* Layer::editLayerSnapshot() {
+LayerSnapshot* Layer::editLayerSnapshot() {
     return mSnapshot.get();
 }
+
 const compositionengine::LayerFECompositionState* Layer::getCompositionState() const {
     return mSnapshot.get();
 }
 
+void Layer::moveSnapshotToLayerFE() {
+    mLayerFE->mSnapshot = std::move(mSnapshot);
+}
+
+void Layer::moveSnapshotToLayer() {
+    mSnapshot = std::move(mLayerFE->mSnapshot);
+}
+
 void Layer::useSurfaceDamage() {
     if (mFlinger->mForceFullDamage) {
         surfaceDamageRegion = Region::INVALID_REGION;
@@ -4154,17 +3889,6 @@
     return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr;
 }
 
-void Layer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const {
-    sp<GraphicBuffer> buffer = getBuffer();
-    if (!buffer) {
-        ALOGE("Buffer should not be null!");
-        return;
-    }
-    GLConsumer::computeTransformMatrix(outMatrix, buffer->getWidth(), buffer->getHeight(),
-                                       buffer->getPixelFormat(), mBufferInfo.mCrop,
-                                       mBufferInfo.mTransform, filteringEnabled);
-}
-
 void Layer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) {
     mTransformHint = getFixedTransformHint();
     if (mTransformHint == ui::Transform::ROT_INVALID) {
@@ -4240,9 +3964,17 @@
     }
     snapshot->bufferSize = getBufferSize(mDrawingState);
     snapshot->externalTexture = mBufferInfo.mBuffer;
+    snapshot->hasReadyFrame = hasReadyFrame();
     preparePerFrameCompositionState();
 }
 
+void Layer::updateChildrenSnapshots(bool updateGeometry) {
+    for (const sp<Layer>& child : mDrawingChildren) {
+        child->updateSnapshot(updateGeometry);
+        child->updateChildrenSnapshots(updateGeometry);
+    }
+}
+
 void Layer::updateMetadataSnapshot(const LayerMetadata& parentMetadata) {
     mSnapshot->layerMetadata = parentMetadata;
     mSnapshot->layerMetadata.merge(mDrawingState.metadata);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 8ace812..da8be6b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -52,6 +52,7 @@
 #include "DisplayHardware/HWComposer.h"
 #include "FrameTracker.h"
 #include "HwcSlotGenerator.h"
+#include "LayerFE.h"
 #include "LayerVector.h"
 #include "Scheduler/LayerInfo.h"
 #include "SurfaceFlinger.h"
@@ -97,7 +98,7 @@
     bool addToRoot = true;
 };
 
-class Layer : public virtual RefBase, compositionengine::LayerFE {
+class Layer : public virtual RefBase {
     static std::atomic<int32_t> sSequence;
     // The following constants represent priority of the window. SF uses this information when
     // deciding which window has a priority when deciding about the refresh rate of the screen.
@@ -129,43 +130,6 @@
         inline bool operator!=(const Geometry& rhs) const { return !operator==(rhs); }
     };
 
-    struct RoundedCornerState {
-        RoundedCornerState() = default;
-        RoundedCornerState(const FloatRect& cropRect, const vec2& radius)
-              : cropRect(cropRect), radius(radius) {}
-
-        // Rounded rectangle in local layer coordinate space.
-        FloatRect cropRect = FloatRect();
-        // Radius of the rounded rectangle.
-        vec2 radius;
-        bool hasRoundedCorners() const { return radius.x > 0.0f && radius.y > 0.0f; }
-    };
-
-    // LayerSnapshot stores Layer state used by Composition Engine and Render Engine. Composition
-    // Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings
-    // passed to Render Engine are created using properties stored on this struct.
-    //
-    // TODO(b/238781169) Implement LayerFE as a separate subclass. Migrate LayerSnapshot to that
-    // LayerFE subclass.
-    struct LayerSnapshot : public compositionengine::LayerFECompositionState {
-        int32_t sequence;
-        std::string name;
-        uint32_t textureName;
-        bool contentOpaque;
-        RoundedCornerState roundedCorner;
-        StretchEffect stretchEffect;
-        FloatRect transformedBounds;
-        renderengine::ShadowSettings shadowSettings;
-        bool premultipliedAlpha;
-        bool isHdrY410;
-        bool bufferNeedsFiltering;
-        ui::Transform transform;
-        Rect bufferSize;
-        std::shared_ptr<renderengine::ExternalTexture> externalTexture;
-        LayerMetadata layerMetadata;
-        LayerMetadata relativeLayerMetadata;
-    };
-
     using FrameRate = scheduler::LayerInfo::FrameRate;
     using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
 
@@ -413,7 +377,16 @@
     ui::Dataspace getDataSpace() const;
     ui::Dataspace getRequestedDataSpace() const;
 
-    virtual sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const;
+    virtual sp<LayerFE> getCompositionEngineLayerFE() const;
+
+    // Move LayerSnapshot from this layer into its LayerFE. This must be called before passing the
+    // LayerFE to CompositionEngine. Moving the snapshot instead of sharing common state
+    // prevents use of LayerFE outside the main thread by making errors obvious (i.e. use outside
+    // the main thread results in SEGFAULTs due to nullptr dereference).
+    void moveSnapshotToLayerFE();
+    // Move LayerSnapshot into this layer from its LayerFE. This must be called after
+    // CompositionEngine has presented the layer.
+    void moveSnapshotToLayer();
 
     const LayerSnapshot* getLayerSnapshot() const;
     LayerSnapshot* editLayerSnapshot();
@@ -557,7 +530,7 @@
     // corner crop does not intersect with its own rounded corner crop.
     virtual RoundedCornerState getRoundedCornerState() const;
 
-    bool hasRoundedCorners() const override { return getRoundedCornerState().hasRoundedCorners(); }
+    bool hasRoundedCorners() const { return getRoundedCornerState().hasRoundedCorners(); }
 
     PixelFormat getPixelFormat() const;
     /**
@@ -598,24 +571,15 @@
     // implements compositionengine::LayerFE
     const compositionengine::LayerFECompositionState* getCompositionState() const;
     bool fenceHasSignaled() const;
-    // Called before composition. updatingOutputGeometryThisFrame is used by ARC++'s Layer subclass.
-    bool onPreComposition(nsecs_t refreshStartTime, bool updatingOutputGeometryThisFrame);
-    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) const override;
+    bool onPreComposition(nsecs_t refreshStartTime);
     void onLayerDisplayed(ftl::SharedFuture<FenceResult>);
 
-    void setWasClientComposed(const sp<Fence>& fence) override {
+    void setWasClientComposed(const sp<Fence>& fence) {
         mLastClientCompositionFence = fence;
         mClearClientCompositionFenceOnLayerDisplayed = false;
     }
 
-    const LayerMetadata* getMetadata() const override { return &mSnapshot->layerMetadata; }
-
-    const LayerMetadata* getRelativeMetadata() const override {
-        return &mSnapshot->relativeLayerMetadata;
-    }
-
-    const char* getDebugName() const override;
+    const char* getDebugName() const;
 
     bool setShadowRadius(float shadowRadius);
 
@@ -640,7 +604,7 @@
     // Compute bounds for the layer and cache the results.
     void computeBounds(FloatRect parentBounds, ui::Transform parentTransform, float shadowRadius);
 
-    int32_t getSequence() const override { return sequence; }
+    int32_t getSequence() const { return sequence; }
 
     // For tracing.
     // TODO: Replace with raw buffer id from buffer metadata when that becomes available.
@@ -902,7 +866,7 @@
 
     // Updates the LayerSnapshot. This must be called prior to sending layer data to
     // CompositionEngine or RenderEngine (i.e. before calling CompositionEngine::present or
-    // Layer::prepareClientComposition).
+    // LayerFE::prepareClientComposition).
     //
     // TODO(b/238781169) Remove direct calls to RenderEngine::drawLayers that don't go through
     // CompositionEngine to create a single path for composing layers.
@@ -928,7 +892,6 @@
     void gatherBufferInfo();
     void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&);
 
-    sp<compositionengine::LayerFE> asLayerFE() const;
     sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
     bool isClone() { return mClonedFrom != nullptr; }
     bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
@@ -941,12 +904,6 @@
     void addChildToDrawing(const sp<Layer>&);
     void updateClonedInputInfo(const std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
 
-    // Modifies the passed in layer settings to clear the contents. If the blackout flag is set,
-    // the settings clears the content with a solid black fill.
-    void prepareClearClientComposition(LayerFE::LayerSettings&, bool blackout) const;
-    void prepareShadowClientComposition(LayerFE::LayerSettings& caster,
-                                        const Rect& layerStackRect) const;
-
     void prepareBasicGeometryCompositionState();
     void prepareGeometryCompositionState();
     void prepareCursorCompositionState();
@@ -1102,10 +1059,6 @@
     // Fills in the frame and transform info for the gui::WindowInfo.
     void fillInputFrameInfo(gui::WindowInfo&, const ui::Transform& screenToDisplay);
 
-    // Computes the transform matrix using the setFilteringEnabled to determine whether the
-    // transform matrix should be computed for use with bilinear filtering.
-    void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) const;
-
     inline void tracePendingBufferCount(int32_t pendingBuffers);
 
     // Latch sideband stream and returns true if the dirty region should be updated.
@@ -1129,8 +1082,6 @@
                                    const sp<Fence>& releaseFence,
                                    uint32_t currentMaxAcquiredBufferCount);
 
-    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientCompositionInternal(
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
     // Returns true if there is a valid color to fill.
     bool fillsColor() const;
     // Returns true if this layer has a blur value.
@@ -1141,12 +1092,8 @@
     }
 
     bool hasSomethingToDraw() const { return hasEffect() || hasBufferOrSidebandStream(); }
-    void prepareBufferStateClientComposition(
-            compositionengine::LayerFE::LayerSettings&,
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
-    void prepareEffectsClientComposition(
-            compositionengine::LayerFE::LayerSettings&,
-            compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+
+    void updateChildrenSnapshots(bool updateGeometry);
 
     // Cached properties computed from drawing state
     // Effective transform taking into account parent transforms and any parent scaling, which is
@@ -1239,6 +1186,7 @@
 
     sp<HwcSlotGenerator> mHwcSlotGenerator;
 
+    sp<LayerFE> mLayerFE;
     std::unique_ptr<LayerSnapshot> mSnapshot = std::make_unique<LayerSnapshot>();
 };
 
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
new file mode 100644
index 0000000..3bdb521
--- /dev/null
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -0,0 +1,386 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "LayerFE"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <gui/GLConsumer.h>
+#include <gui/TraceUtils.h>
+#include <math/vec3.h>
+#include <system/window.h>
+#include <utils/Log.h>
+
+#include "DisplayDevice.h"
+#include "LayerFE.h"
+
+namespace android {
+
+namespace {
+constexpr float defaultMaxLuminance = 1000.0;
+
+constexpr mat4 inverseOrientation(uint32_t transform) {
+    const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+    const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
+    const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
+    mat4 tr;
+
+    if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+        tr = tr * rot90;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
+        tr = tr * flipH;
+    }
+    if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
+        tr = tr * flipV;
+    }
+    return inverse(tr);
+}
+
+FloatRect reduce(const FloatRect& win, const Region& exclude) {
+    if (CC_LIKELY(exclude.isEmpty())) {
+        return win;
+    }
+    // Convert through Rect (by rounding) for lack of FloatRegion
+    return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
+}
+
+// Computes the transform matrix using the setFilteringEnabled to determine whether the
+// transform matrix should be computed for use with bilinear filtering.
+void getDrawingTransformMatrix(const std::shared_ptr<renderengine::ExternalTexture>& buffer,
+                               Rect bufferCrop, uint32_t bufferTransform, bool filteringEnabled,
+                               float outMatrix[16]) {
+    if (!buffer) {
+        ALOGE("Buffer should not be null!");
+        return;
+    }
+    GLConsumer::computeTransformMatrix(outMatrix, static_cast<float>(buffer->getWidth()),
+                                       static_cast<float>(buffer->getHeight()),
+                                       buffer->getPixelFormat(), bufferCrop, bufferTransform,
+                                       filteringEnabled);
+}
+
+} // namespace
+
+LayerFE::LayerFE(const std::string& name) : mName(name) {}
+
+const compositionengine::LayerFECompositionState* LayerFE::getCompositionState() const {
+    return mSnapshot.get();
+}
+
+bool LayerFE::onPreComposition(nsecs_t refreshStartTime, bool) {
+    mCompositionResult.refreshStartTime = refreshStartTime;
+    return mSnapshot->hasReadyFrame;
+}
+
+std::optional<compositionengine::LayerFE::LayerSettings> LayerFE::prepareClientComposition(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+    std::optional<compositionengine::LayerFE::LayerSettings> layerSettings =
+            prepareClientCompositionInternal(targetSettings);
+    // Nothing to render.
+    if (!layerSettings) {
+        return {};
+    }
+
+    // HWC requests to clear this layer.
+    if (targetSettings.clearContent) {
+        prepareClearClientComposition(*layerSettings, false /* blackout */);
+        return layerSettings;
+    }
+
+    // set the shadow for the layer if needed
+    prepareShadowClientComposition(*layerSettings, targetSettings.viewport);
+
+    return layerSettings;
+}
+
+std::optional<compositionengine::LayerFE::LayerSettings> LayerFE::prepareClientCompositionInternal(
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+    ATRACE_CALL();
+    compositionengine::LayerFE::LayerSettings layerSettings;
+    layerSettings.geometry.boundaries =
+            reduce(mSnapshot->geomLayerBounds, mSnapshot->transparentRegionHint);
+    layerSettings.geometry.positionTransform = mSnapshot->geomLayerTransform.asMatrix4();
+
+    // skip drawing content if the targetSettings indicate the content will be occluded
+    const bool drawContent = targetSettings.realContentIsVisible || targetSettings.clearContent;
+    layerSettings.skipContentDraw = !drawContent;
+
+    if (!mSnapshot->colorTransformIsIdentity) {
+        layerSettings.colorTransform = mSnapshot->colorTransform;
+    }
+
+    const auto& roundedCornerState = mSnapshot->roundedCorner;
+    layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius;
+    layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+
+    layerSettings.alpha = mSnapshot->alpha;
+    layerSettings.sourceDataspace = mSnapshot->dataspace;
+
+    // Override the dataspace transfer from 170M to sRGB if the device configuration requests this.
+    // We do this here instead of in buffer info so that dumpsys can still report layers that are
+    // using the 170M transfer.
+    if (targetSettings.treat170mAsSrgb &&
+        (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) ==
+                HAL_DATASPACE_TRANSFER_SMPTE_170M) {
+        layerSettings.sourceDataspace = static_cast<ui::Dataspace>(
+                (layerSettings.sourceDataspace & HAL_DATASPACE_STANDARD_MASK) |
+                (layerSettings.sourceDataspace & HAL_DATASPACE_RANGE_MASK) |
+                HAL_DATASPACE_TRANSFER_SRGB);
+    }
+
+    layerSettings.whitePointNits = targetSettings.whitePointNits;
+    switch (targetSettings.blurSetting) {
+        case LayerFE::ClientCompositionTargetSettings::BlurSetting::Enabled:
+            layerSettings.backgroundBlurRadius = mSnapshot->backgroundBlurRadius;
+            layerSettings.blurRegions = mSnapshot->blurRegions;
+            layerSettings.blurRegionTransform = mSnapshot->geomInverseLayerTransform.asMatrix4();
+            break;
+        case LayerFE::ClientCompositionTargetSettings::BlurSetting::BackgroundBlurOnly:
+            layerSettings.backgroundBlurRadius = mSnapshot->backgroundBlurRadius;
+            break;
+        case LayerFE::ClientCompositionTargetSettings::BlurSetting::BlurRegionsOnly:
+            layerSettings.blurRegions = mSnapshot->blurRegions;
+            layerSettings.blurRegionTransform = mSnapshot->geomInverseLayerTransform.asMatrix4();
+            break;
+        case LayerFE::ClientCompositionTargetSettings::BlurSetting::Disabled:
+        default:
+            break;
+    }
+    layerSettings.stretchEffect = mSnapshot->stretchEffect;
+    // Record the name of the layer for debugging further down the stack.
+    layerSettings.name = mSnapshot->name;
+
+    if (hasEffect() && !hasBufferOrSidebandStream()) {
+        prepareEffectsClientComposition(layerSettings, targetSettings);
+        return layerSettings;
+    }
+
+    prepareBufferStateClientComposition(layerSettings, targetSettings);
+    return layerSettings;
+}
+
+void LayerFE::prepareClearClientComposition(LayerFE::LayerSettings& layerSettings,
+                                            bool blackout) const {
+    layerSettings.source.buffer.buffer = nullptr;
+    layerSettings.source.solidColor = half3(0.0f, 0.0f, 0.0f);
+    layerSettings.disableBlending = true;
+    layerSettings.bufferId = 0;
+    layerSettings.frameNumber = 0;
+
+    // If layer is blacked out, force alpha to 1 so that we draw a black color layer.
+    layerSettings.alpha = blackout ? 1.0f : 0.0f;
+    layerSettings.name = mSnapshot->name;
+}
+
+void LayerFE::prepareEffectsClientComposition(
+        compositionengine::LayerFE::LayerSettings& layerSettings,
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+    // If fill bounds are occluded or the fill color is invalid skip the fill settings.
+    if (targetSettings.realContentIsVisible && fillsColor()) {
+        // Set color for color fill settings.
+        layerSettings.source.solidColor = mSnapshot->color.rgb;
+    } else if (hasBlur() || drawShadows()) {
+        layerSettings.skipContentDraw = true;
+    }
+}
+
+void LayerFE::prepareBufferStateClientComposition(
+        compositionengine::LayerFE::LayerSettings& layerSettings,
+        compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) const {
+    ATRACE_CALL();
+    if (CC_UNLIKELY(!mSnapshot->externalTexture)) {
+        // If there is no buffer for the layer or we have sidebandstream where there is no
+        // activeBuffer, then we need to return LayerSettings.
+        return;
+    }
+    const bool blackOutLayer =
+            (mSnapshot->hasProtectedContent && !targetSettings.supportsProtectedContent) ||
+            ((mSnapshot->isSecure || mSnapshot->hasProtectedContent) && !targetSettings.isSecure);
+    const bool bufferCanBeUsedAsHwTexture =
+            mSnapshot->externalTexture->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE;
+    if (blackOutLayer || !bufferCanBeUsedAsHwTexture) {
+        ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable",
+                 mSnapshot->name.c_str());
+        prepareClearClientComposition(layerSettings, true /* blackout */);
+        return;
+    }
+
+    layerSettings.source.buffer.buffer = mSnapshot->externalTexture;
+    layerSettings.source.buffer.isOpaque = mSnapshot->contentOpaque;
+    layerSettings.source.buffer.fence = mSnapshot->acquireFence;
+    layerSettings.source.buffer.textureName = mSnapshot->textureName;
+    layerSettings.source.buffer.usePremultipliedAlpha = mSnapshot->premultipliedAlpha;
+    layerSettings.source.buffer.isY410BT2020 = mSnapshot->isHdrY410;
+    bool hasSmpte2086 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::SMPTE2086;
+    bool hasCta861_3 = mSnapshot->hdrMetadata.validTypes & HdrMetadata::CTA861_3;
+    float maxLuminance = 0.f;
+    if (hasSmpte2086 && hasCta861_3) {
+        maxLuminance = std::min(mSnapshot->hdrMetadata.smpte2086.maxLuminance,
+                                mSnapshot->hdrMetadata.cta8613.maxContentLightLevel);
+    } else if (hasSmpte2086) {
+        maxLuminance = mSnapshot->hdrMetadata.smpte2086.maxLuminance;
+    } else if (hasCta861_3) {
+        maxLuminance = mSnapshot->hdrMetadata.cta8613.maxContentLightLevel;
+    } else {
+        switch (layerSettings.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) {
+            case HAL_DATASPACE_TRANSFER_ST2084:
+            case HAL_DATASPACE_TRANSFER_HLG:
+                // Behavior-match previous releases for HDR content
+                maxLuminance = defaultMaxLuminance;
+                break;
+        }
+    }
+    layerSettings.source.buffer.maxLuminanceNits = maxLuminance;
+    layerSettings.frameNumber = mSnapshot->frameNumber;
+    layerSettings.bufferId = mSnapshot->externalTexture->getId();
+
+    const bool useFiltering = targetSettings.needsFiltering ||
+            mSnapshot->geomLayerTransform.needsBilinearFiltering() ||
+            mSnapshot->bufferNeedsFiltering;
+
+    // Query the texture matrix given our current filtering mode.
+    float textureMatrix[16];
+    getDrawingTransformMatrix(layerSettings.source.buffer.buffer, mSnapshot->geomContentCrop,
+                              mSnapshot->geomBufferTransform, useFiltering, textureMatrix);
+
+    if (mSnapshot->geomBufferUsesDisplayInverseTransform) {
+        /*
+         * the code below applies the primary display's inverse transform to
+         * the texture transform
+         */
+        uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
+        mat4 tr = inverseOrientation(transform);
+
+        /**
+         * TODO(b/36727915): This is basically a hack.
+         *
+         * Ensure that regardless of the parent transformation,
+         * this buffer is always transformed from native display
+         * orientation to display orientation. For example, in the case
+         * of a camera where the buffer remains in native orientation,
+         * we want the pixels to always be upright.
+         */
+        const auto parentTransform = mSnapshot->transform;
+        tr = tr * inverseOrientation(parentTransform.getOrientation());
+
+        // and finally apply it to the original texture matrix
+        const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr);
+        memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix));
+    }
+
+    const Rect win{layerSettings.geometry.boundaries};
+    float bufferWidth = static_cast<float>(mSnapshot->bufferSize.getWidth());
+    float bufferHeight = static_cast<float>(mSnapshot->bufferSize.getHeight());
+
+    // Layers can have a "buffer size" of [0, 0, -1, -1] when no display frame has
+    // been set and there is no parent layer bounds. In that case, the scale is meaningless so
+    // ignore them.
+    if (!mSnapshot->bufferSize.isValid()) {
+        bufferWidth = float(win.right) - float(win.left);
+        bufferHeight = float(win.bottom) - float(win.top);
+    }
+
+    const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight;
+    const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth;
+    const float translateY = float(win.top) / bufferHeight;
+    const float translateX = float(win.left) / bufferWidth;
+
+    // Flip y-coordinates because GLConsumer expects OpenGL convention.
+    mat4 tr = mat4::translate(vec4(.5f, .5f, 0.f, 1.f)) * mat4::scale(vec4(1.f, -1.f, 1.f, 1.f)) *
+            mat4::translate(vec4(-.5f, -.5f, 0.f, 1.f)) *
+            mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) *
+            mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f));
+
+    layerSettings.source.buffer.useTextureFiltering = useFiltering;
+    layerSettings.source.buffer.textureTransform =
+            mat4(static_cast<const float*>(textureMatrix)) * tr;
+
+    return;
+}
+
+void LayerFE::prepareShadowClientComposition(LayerFE::LayerSettings& caster,
+                                             const Rect& layerStackRect) const {
+    renderengine::ShadowSettings state = mSnapshot->shadowSettings;
+    if (state.length <= 0.f || (state.ambientColor.a <= 0.f && state.spotColor.a <= 0.f)) {
+        return;
+    }
+
+    // Shift the spot light x-position to the middle of the display and then
+    // offset it by casting layer's screen pos.
+    state.lightPos.x =
+            (static_cast<float>(layerStackRect.width()) / 2.f) - mSnapshot->transformedBounds.left;
+    state.lightPos.y -= mSnapshot->transformedBounds.top;
+    caster.shadow = state;
+}
+
+void LayerFE::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
+    mCompositionResult.releaseFences.emplace_back(std::move(futureFenceResult));
+}
+
+CompositionResult&& LayerFE::stealCompositionResult() {
+    return std::move(mCompositionResult);
+}
+
+const char* LayerFE::getDebugName() const {
+    return mName.c_str();
+}
+
+const LayerMetadata* LayerFE::getMetadata() const {
+    return &mSnapshot->layerMetadata;
+}
+
+const LayerMetadata* LayerFE::getRelativeMetadata() const {
+    return &mSnapshot->relativeLayerMetadata;
+}
+
+int32_t LayerFE::getSequence() const {
+    return mSnapshot->sequence;
+}
+
+bool LayerFE::hasRoundedCorners() const {
+    return mSnapshot->roundedCorner.hasRoundedCorners();
+}
+
+void LayerFE::setWasClientComposed(const sp<Fence>& fence) {
+    mCompositionResult.lastClientCompositionFence = fence;
+}
+
+bool LayerFE::hasBufferOrSidebandStream() const {
+    return mSnapshot->externalTexture || mSnapshot->sidebandStream;
+}
+
+bool LayerFE::fillsColor() const {
+    return mSnapshot->color.r >= 0.0_hf && mSnapshot->color.g >= 0.0_hf &&
+            mSnapshot->color.b >= 0.0_hf;
+}
+
+bool LayerFE::hasBlur() const {
+    return mSnapshot->backgroundBlurRadius > 0 || mSnapshot->blurRegions.size() > 0;
+}
+
+bool LayerFE::drawShadows() const {
+    return mSnapshot->shadowSettings.length > 0.f &&
+            (mSnapshot->shadowSettings.ambientColor.a > 0 ||
+             mSnapshot->shadowSettings.spotColor.a > 0);
+};
+
+const sp<GraphicBuffer> LayerFE::getBuffer() const {
+    return mSnapshot->externalTexture ? mSnapshot->externalTexture->getBuffer() : nullptr;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/LayerFE.h b/services/surfaceflinger/LayerFE.h
new file mode 100644
index 0000000..e4f6889
--- /dev/null
+++ b/services/surfaceflinger/LayerFE.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gui/LayerMetadata.h>
+
+#include "compositionengine/LayerFE.h"
+#include "compositionengine/LayerFECompositionState.h"
+#include "renderengine/LayerSettings.h"
+
+namespace android {
+struct RoundedCornerState {
+    RoundedCornerState() = default;
+    RoundedCornerState(const FloatRect& cropRect, const vec2& radius)
+          : cropRect(cropRect), radius(radius) {}
+
+    // Rounded rectangle in local layer coordinate space.
+    FloatRect cropRect = FloatRect();
+    // Radius of the rounded rectangle.
+    vec2 radius;
+    bool hasRoundedCorners() const { return radius.x > 0.0f && radius.y > 0.0f; }
+};
+
+// LayerSnapshot stores Layer state used by CompositionEngine and RenderEngine. Composition
+// Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings
+// passed to Render Engine are created using properties stored on this struct.
+struct LayerSnapshot : public compositionengine::LayerFECompositionState {
+    int32_t sequence;
+    std::string name;
+    uint32_t textureName;
+    bool contentOpaque;
+    RoundedCornerState roundedCorner;
+    StretchEffect stretchEffect;
+    FloatRect transformedBounds;
+    renderengine::ShadowSettings shadowSettings;
+    bool premultipliedAlpha;
+    bool isHdrY410;
+    bool bufferNeedsFiltering;
+    ui::Transform transform;
+    Rect bufferSize;
+    std::shared_ptr<renderengine::ExternalTexture> externalTexture;
+    gui::LayerMetadata layerMetadata;
+    gui::LayerMetadata relativeLayerMetadata;
+    bool contentDirty;
+    bool hasReadyFrame;
+};
+
+struct CompositionResult {
+    // TODO(b/238781169) update CE to no longer pass refreshStartTime to LayerFE::onPreComposition
+    // and remove this field.
+    nsecs_t refreshStartTime = 0;
+    std::vector<ftl::SharedFuture<FenceResult>> releaseFences;
+    sp<Fence> lastClientCompositionFence = nullptr;
+};
+
+class LayerFE : public virtual RefBase, public virtual compositionengine::LayerFE {
+public:
+    LayerFE(const std::string& name);
+
+    // compositionengine::LayerFE overrides
+    const compositionengine::LayerFECompositionState* getCompositionState() const override;
+    bool onPreComposition(nsecs_t refreshStartTime, bool updatingOutputGeometryThisFrame) override;
+    void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override;
+    const char* getDebugName() const override;
+    int32_t getSequence() const override;
+    bool hasRoundedCorners() const override;
+    void setWasClientComposed(const sp<Fence>&) override;
+    const gui::LayerMetadata* getMetadata() const override;
+    const gui::LayerMetadata* getRelativeMetadata() const override;
+    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+    CompositionResult&& stealCompositionResult();
+
+    std::unique_ptr<LayerSnapshot> mSnapshot;
+
+private:
+    std::optional<compositionengine::LayerFE::LayerSettings> prepareClientCompositionInternal(
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+    // Modifies the passed in layer settings to clear the contents. If the blackout flag is set,
+    // the settings clears the content with a solid black fill.
+    void prepareClearClientComposition(LayerFE::LayerSettings&, bool blackout) const;
+    void prepareShadowClientComposition(LayerFE::LayerSettings& caster,
+                                        const Rect& layerStackRect) const;
+    void prepareBufferStateClientComposition(
+            compositionengine::LayerFE::LayerSettings&,
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+    void prepareEffectsClientComposition(
+            compositionengine::LayerFE::LayerSettings&,
+            compositionengine::LayerFE::ClientCompositionTargetSettings&) const;
+
+    bool hasEffect() const { return fillsColor() || drawShadows() || hasBlur(); }
+    bool hasBufferOrSidebandStream() const;
+
+    bool fillsColor() const;
+    bool hasBlur() const;
+    bool drawShadows() const;
+
+    const sp<GraphicBuffer> getBuffer() const;
+
+    CompositionResult mCompositionResult;
+    std::string mName;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 6bc7dc1..3e6ed41 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -30,6 +30,7 @@
         // Compute and cache the bounds for the new parent layer.
         newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(),
             0.f /* shadowRadius */);
+        newParent->updateSnapshot(true /* updateGeometry */);
         oldParent->setChildrenDrawingParent(newParent);
 };
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e4fee1c..6144a2f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2172,10 +2172,14 @@
 
     refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
     refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
-    mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
+    std::vector<Layer*> layers;
+
+    mDrawingState.traverseInZOrder([&refreshArgs, &layers](Layer* layer) {
         layer->updateSnapshot(refreshArgs.updatingGeometryThisFrame);
         if (auto layerFE = layer->getCompositionEngineLayerFE()) {
+            layer->moveSnapshotToLayerFE();
             refreshArgs.layers.push_back(layerFE);
+            layers.push_back(layer);
         }
     });
     refreshArgs.blursAreExpensive = mBlursAreExpensive;
@@ -2207,6 +2211,19 @@
 
     mCompositionEngine->present(refreshArgs);
 
+    for (auto& layer : layers) {
+        layer->moveSnapshotToLayer();
+        CompositionResult compositionResult{
+                layer->getCompositionEngineLayerFE()->stealCompositionResult()};
+        layer->onPreComposition(compositionResult.refreshStartTime);
+        for (auto releaseFence : compositionResult.releaseFences) {
+            layer->onLayerDisplayed(releaseFence);
+        }
+        if (compositionResult.lastClientCompositionFence) {
+            layer->setWasClientComposed(compositionResult.lastClientCompositionFence);
+        }
+    }
+
     mTimeStats->recordFrameDuration(frameTime.ns(), systemTime());
 
     // Send a power hint hint after presentation is finished
@@ -3291,7 +3308,21 @@
         }
     }
 
+    std::vector<Layer*> cursorLayers;
+    mDrawingState.traverse([&cursorLayers](Layer* layer) {
+        if (layer->getLayerSnapshot()->compositionType ==
+            aidl::android::hardware::graphics::composer3::Composition::CURSOR) {
+            layer->updateSnapshot(false /* updateGeometry */);
+            layer->moveSnapshotToLayerFE();
+            cursorLayers.push_back(layer);
+        }
+    });
+
     mCompositionEngine->updateCursorAsync(refreshArgs);
+
+    for (Layer* layer : cursorLayers) {
+        layer->moveSnapshotToLayer();
+    }
 }
 
 void SurfaceFlinger::requestDisplayModes(
@@ -6444,8 +6475,16 @@
                 isHdrLayer(layer) ? displayBrightnessNits : sdrWhitePointNits,
 
         };
+        auto layerFE = layer->getCompositionEngineLayerFE();
+        if (!layerFE) {
+            return;
+        }
+
+        layer->moveSnapshotToLayerFE();
         std::optional<compositionengine::LayerFE::LayerSettings> settings =
-                layer->prepareClientComposition(targetSettings);
+                layerFE->prepareClientComposition(targetSettings);
+        layer->moveSnapshotToLayer();
+
         if (!settings) {
             return;
         }
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index 2f1f263..7e6894d 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -91,6 +91,10 @@
     return sp<Layer>::make(args);
 }
 
+sp<LayerFE> DefaultFactory::createLayerFE(const std::string& layerName) {
+    return sp<LayerFE>::make(layerName);
+}
+
 std::unique_ptr<FrameTracer> DefaultFactory::createFrameTracer() {
     return std::make_unique<FrameTracer>();
 }
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 447a02f..2c6de0e 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -42,6 +42,7 @@
     std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override;
     sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) override;
     sp<Layer> createEffectLayer(const LayerCreationArgs& args) override;
+    sp<LayerFE> createLayerFE(const std::string& layerName) override;
     std::unique_ptr<FrameTracer> createFrameTracer() override;
     std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
             std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) override;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 9c4d5c8..d1f21bf 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -38,6 +38,7 @@
 class IGraphicBufferConsumer;
 class IGraphicBufferProducer;
 class Layer;
+class LayerFE;
 class StartPropertySetThread;
 class SurfaceFlinger;
 class TimeStats;
@@ -88,6 +89,7 @@
 
     virtual sp<Layer> createBufferStateLayer(const LayerCreationArgs& args) = 0;
     virtual sp<Layer> createEffectLayer(const LayerCreationArgs& args) = 0;
+    virtual sp<LayerFE> createLayerFE(const std::string& layerName) = 0;
     virtual std::unique_ptr<FrameTracer> createFrameTracer() = 0;
     virtual std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
             std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid) = 0;
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index d0364f2..276b3da 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -82,6 +82,8 @@
 
     sp<Layer> createEffectLayer(const LayerCreationArgs& args) { return sp<Layer>::make(args); }
 
+    sp<LayerFE> createLayerFE(const std::string& layerName) { return sp<LayerFE>::make(layerName); }
+
     std::unique_ptr<FrameTracer> createFrameTracer() override {
         return std::make_unique<testing::NiceMock<mock::FrameTracer>>();
     }
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index ed2fe23..e2ae4f4 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -354,6 +354,10 @@
         return sp<Layer>::make(args);
     }
 
+    sp<LayerFE> createLayerFE(const std::string &layerName) override {
+        return sp<LayerFE>::make(layerName);
+    }
+
     std::unique_ptr<FrameTracer> createFrameTracer() override {
         return std::make_unique<android::mock::FrameTracer>();
     }
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
index 0a142c3..acfc1d4 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp
@@ -146,8 +146,7 @@
     layer->computeSourceBounds(getFuzzedFloatRect(&mFdp));
 
     layer->fenceHasSignaled();
-    layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>(),
-                            false /*updatingOutputGeometryThisFrame*/);
+    layer->onPreComposition(mFdp.ConsumeIntegral<int64_t>());
     const std::vector<sp<CallbackHandle>> callbacks;
     layer->setTransactionCompletedListeners(callbacks);
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 29ff5ee..83d852a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -118,6 +118,10 @@
 
     sp<Layer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
 
+    sp<LayerFE> createLayerFE(const std::string& layerName) override {
+        return sp<LayerFE>::make(layerName);
+    }
+
     std::unique_ptr<FrameTracer> createFrameTracer() override {
         return std::make_unique<mock::FrameTracer>();
     }