Merge "Game Driver: plumb driver choice and loading time to GpuStats"
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index 273a5a6..1bf55e4 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -23,7 +23,7 @@
 ## To build, deploy, and take a bugreport
 
 ```
-mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb shell am bug-report
+mmm -j frameworks/native/cmds/dumpstate && adb push ${OUT}/system/bin/dumpstate system/bin && adb push ${OUT}/system/lib64/*dumpstate*.so /system/lib64/ && adb shell am bug-report
 ```
 
 Make sure that the device is remounted before running the above command.
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index db8848a..2a28627 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -113,6 +113,7 @@
 #define LOGPERSIST_DATA_DIR "/data/misc/logd"
 #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur"
 #define PROFILE_DATA_DIR_REF "/data/misc/profiles/ref"
+#define XFRM_STAT_PROC_FILE "/proc/net/xfrm_stat"
 #define WLUTIL "/vendor/xbin/wlutil"
 #define WMTRACE_DATA_DIR "/data/misc/wmtrace"
 
@@ -1455,15 +1456,24 @@
     add_mountinfo();
     DumpIpTablesAsRoot();
 
-    // Capture any IPSec policies in play.  No keys are exposed here.
+    // Capture any IPSec policies in play. No keys are exposed here.
     RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build());
 
+    // Dump IPsec stats. No keys are exposed here.
+    DumpFile("XFRM STATS", XFRM_STAT_PROC_FILE);
+
     // Run ss as root so we can see socket marks.
     RunCommand("DETAILED SOCKET STATE", {"ss", "-eionptu"}, CommandOptions::WithTimeout(10).Build());
 
     // Run iotop as root to show top 100 IO threads
     RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
 
+    // Gather shared memory buffer info if the product implements it
+    struct stat st;
+    if (!stat("/product/bin/dmabuf_dump", &st)) {
+        RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
+    }
+
     if (!DropRootUser()) {
         return false;
     }
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 46b9128..bf2a03d 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -383,6 +383,7 @@
     other.mListenerCallbacks.clear();
 
     mInputWindowCommands.merge(other.mInputWindowCommands);
+    other.mInputWindowCommands.clear();
 
     return *this;
 }
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index 604665b..da91a97 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -78,15 +78,14 @@
     BufferHubStatus ret;
     sp<IBufferClient> client;
     BufferTraits bufferTraits;
-    IBufferHub::allocateBuffer_cb alloc_cb = [&](const auto& status, const auto& outClient,
-                                                 const auto& outTraits) {
+    IBufferHub::allocateBuffer_cb allocCb = [&](const auto& status, const auto& outClient,
+                                                const auto& outTraits) {
         ret = status;
         client = std::move(outClient);
         bufferTraits = std::move(outTraits);
     };
 
-    if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), alloc_cb)
-                 .isOk()) {
+    if (!bufferhub->allocateBuffer(desc, static_cast<uint32_t>(userMetadataSize), allocCb).isOk()) {
         ALOGE("%s: allocateBuffer transaction failed!", __FUNCTION__);
         return;
     } else if (ret != BufferHubStatus::NO_ERROR) {
@@ -115,8 +114,8 @@
     BufferHubStatus ret;
     sp<IBufferClient> client;
     BufferTraits bufferTraits;
-    IBufferHub::importBuffer_cb import_cb = [&](const auto& status, const auto& outClient,
-                                                const auto& outTraits) {
+    IBufferHub::importBuffer_cb importCb = [&](const auto& status, const auto& outClient,
+                                               const auto& outTraits) {
         ret = status;
         client = std::move(outClient);
         bufferTraits = std::move(outTraits);
@@ -124,7 +123,7 @@
 
     // hidl_handle(native_handle_t*) simply creates a raw pointer reference withouth ownership
     // transfer.
-    if (!bufferhub->importBuffer(hidl_handle(token.get()->handle()), import_cb).isOk()) {
+    if (!bufferhub->importBuffer(hidl_handle(token.get()->handle()), importCb).isOk()) {
         ALOGE("%s: importBuffer transaction failed!", __FUNCTION__);
         return;
     } else if (ret != BufferHubStatus::NO_ERROR) {
@@ -210,9 +209,9 @@
 
     // Populate shortcuts to the atomics in metadata.
     auto metadataHeader = mMetadata.metadataHeader();
-    mBufferState = &metadataHeader->buffer_state;
-    mFenceState = &metadataHeader->fence_state;
-    mActiveClientsBitMask = &metadataHeader->active_clients_bit_mask;
+    mBufferState = &metadataHeader->bufferState;
+    mFenceState = &metadataHeader->fenceState;
+    mActiveClientsBitMask = &metadataHeader->activeClientsBitMask;
     // The C++ standard recommends (but does not require) that lock-free atomic operations are
     // also address-free, that is, suitable for communication between processes using shared
     // memory.
@@ -230,7 +229,7 @@
     mClientStateMask = clientBitMask;
 
     // TODO(b/112012161) Set up shared fences.
-    ALOGD("%s: id=%d, buffer_state=%" PRIx32 ".", __FUNCTION__, mId,
+    ALOGD("%s: id=%d, mBufferState=%" PRIx32 ".", __FUNCTION__, mId,
           mBufferState->load(std::memory_order_acquire));
     return 0;
 }
@@ -336,12 +335,12 @@
 
     hidl_handle token;
     BufferHubStatus ret;
-    IBufferClient::duplicate_cb dup_cb = [&](const auto& outToken, const auto& status) {
+    IBufferClient::duplicate_cb dupCb = [&](const auto& outToken, const auto& status) {
         token = std::move(outToken);
         ret = status;
     };
 
-    if (!mBufferClient->duplicate(dup_cb).isOk()) {
+    if (!mBufferClient->duplicate(dupCb).isOk()) {
         ALOGE("%s: duplicate transaction failed!", __FUNCTION__);
         return nullptr;
     } else if (ret != BufferHubStatus::NO_ERROR) {
diff --git a/libs/ui/include/ui/BufferHubBuffer.h b/libs/ui/include/ui/BufferHubBuffer.h
index 5c09032..5ba189c 100644
--- a/libs/ui/include/ui/BufferHubBuffer.h
+++ b/libs/ui/include/ui/BufferHubBuffer.h
@@ -57,7 +57,7 @@
 
     const BufferHubEventFd& eventFd() const { return mEventFd; }
 
-    // Returns the current value of MetadataHeader::buffer_state.
+    // Returns the current value of MetadataHeader::bufferState.
     uint32_t bufferState() const { return mBufferState->load(std::memory_order_acquire); }
 
     // A state mask which is unique to a buffer hub client among all its siblings sharing the same
diff --git a/libs/ui/include/ui/BufferHubDefs.h b/libs/ui/include/ui/BufferHubDefs.h
index 722a060..10f274f 100644
--- a/libs/ui/include/ui/BufferHubDefs.h
+++ b/libs/ui/include/ui/BufferHubDefs.h
@@ -32,7 +32,7 @@
 // Single buffer clients (up to 16) ownership signal.
 // 32-bit atomic unsigned int.
 // Each client takes 2 bits. The first bit locates in the first 16 bits of
-// buffer_state; the second bit locates in the last 16 bits of buffer_state.
+// bufferState; the second bit locates in the last 16 bits of bufferState.
 // Client states:
 // Gained state 11. Exclusive write state.
 // Posted state 10.
@@ -64,9 +64,9 @@
 
 // Returns true if any of the client is in gained state.
 static inline bool isAnyClientGained(uint32_t state) {
-    uint32_t high_bits = state >> kMaxNumberOfClients;
-    uint32_t low_bits = state & kLowbitsMask;
-    return high_bits == low_bits && low_bits != 0U;
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    return highBits == lowBits && lowBits != 0U;
 }
 
 // Returns true if the input client is in gained state.
@@ -76,34 +76,34 @@
 
 // Returns true if any of the client is in posted state.
 static inline bool isAnyClientPosted(uint32_t state) {
-    uint32_t high_bits = state >> kMaxNumberOfClients;
-    uint32_t low_bits = state & kLowbitsMask;
-    uint32_t posted_or_acquired = high_bits ^ low_bits;
-    return posted_or_acquired & high_bits;
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    uint32_t postedOrAcquired = highBits ^ lowBits;
+    return postedOrAcquired & highBits;
 }
 
 // Returns true if the input client is in posted state.
 static inline bool isClientPosted(uint32_t state, uint32_t client_bit_mask) {
-    uint32_t client_bits = state & client_bit_mask;
-    if (client_bits == 0U) return false;
-    uint32_t low_bits = client_bits & kLowbitsMask;
-    return low_bits == 0U;
+    uint32_t clientBits = state & client_bit_mask;
+    if (clientBits == 0U) return false;
+    uint32_t lowBits = clientBits & kLowbitsMask;
+    return lowBits == 0U;
 }
 
 // Return true if any of the client is in acquired state.
 static inline bool isAnyClientAcquired(uint32_t state) {
-    uint32_t high_bits = state >> kMaxNumberOfClients;
-    uint32_t low_bits = state & kLowbitsMask;
-    uint32_t posted_or_acquired = high_bits ^ low_bits;
-    return posted_or_acquired & low_bits;
+    uint32_t highBits = state >> kMaxNumberOfClients;
+    uint32_t lowBits = state & kLowbitsMask;
+    uint32_t postedOrAcquired = highBits ^ lowBits;
+    return postedOrAcquired & lowBits;
 }
 
 // Return true if the input client is in acquired state.
 static inline bool isClientAcquired(uint32_t state, uint32_t client_bit_mask) {
-    uint32_t client_bits = state & client_bit_mask;
-    if (client_bits == 0U) return false;
-    uint32_t high_bits = client_bits & kHighBitsMask;
-    return high_bits == 0U;
+    uint32_t clientBits = state & client_bit_mask;
+    if (clientBits == 0U) return false;
+    uint32_t highBits = clientBits & kHighBitsMask;
+    return highBits == 0U;
 }
 
 // Returns true if the input client is in released state.
@@ -114,12 +114,12 @@
 // Returns the next available buffer client's client_state_masks.
 // @params union_bits. Union of all existing clients' client_state_masks.
 static inline uint32_t findNextAvailableClientStateMask(uint32_t union_bits) {
-    uint32_t low_union = union_bits & kLowbitsMask;
-    if (low_union == kLowbitsMask) return 0U;
-    uint32_t incremented = low_union + 1U;
-    uint32_t difference = incremented ^ low_union;
-    uint32_t new_low_bit = (difference + 1U) >> 1;
-    return new_low_bit + (new_low_bit << kMaxNumberOfClients);
+    uint32_t lowUnion = union_bits & kLowbitsMask;
+    if (lowUnion == kLowbitsMask) return 0U;
+    uint32_t incremented = lowUnion + 1U;
+    uint32_t difference = incremented ^ lowUnion;
+    uint32_t newLowBit = (difference + 1U) >> 1;
+    return newLowBit + (newLowBit << kMaxNumberOfClients);
 }
 
 struct __attribute__((aligned(8))) MetadataHeader {
@@ -129,22 +129,22 @@
     // platform (include Apps and vendor HAL).
 
     // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
-    // buffer_state.
-    std::atomic<uint32_t> buffer_state;
+    // bufferState.
+    std::atomic<uint32_t> bufferState;
 
-    // Every client takes up one bit in fence_state. Only the lower 32 bits are valid. The upper 32
+    // Every client takes up one bit in fenceState. Only the lower 32 bits are valid. The upper 32
     // bits are there for easier manipulation, but the value should be ignored.
-    std::atomic<uint32_t> fence_state;
+    std::atomic<uint32_t> fenceState;
 
     // Every client takes up one bit from the higher 32 bits and one bit from the lower 32 bits in
-    // active_clients_bit_mask.
-    std::atomic<uint32_t> active_clients_bit_mask;
+    // activeClientsBitMask.
+    std::atomic<uint32_t> activeClientsBitMask;
 
     // Explicit padding 4 bytes.
     uint32_t padding;
 
     // The index of the buffer queue where the buffer belongs to.
-    uint64_t queue_index;
+    uint64_t queueIndex;
 
     // Public data format, which should be updated with caution. See more details in dvr_api.h
     DvrNativeBufferMetadata metadata;
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index 634bce1..efc1a80 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -214,8 +214,8 @@
     native_handle_t* token = native_handle_create(/*numFds=*/0, /*numInts=*/1);
     token->data[0] = 0;
 
-    auto b1 = BufferHubBuffer::import(NativeHandle::create(token, /*ownHandle=*/true));
-    native_handle_delete(token);
+    sp<NativeHandle> tokenHandle = NativeHandle::create(token, /*ownHandle=*/true);
+    auto b1 = BufferHubBuffer::import(tokenHandle);
 
     EXPECT_THAT(b1, IsNull());
 }
diff --git a/libs/ui/tests/BufferHubMetadata_test.cpp b/libs/ui/tests/BufferHubMetadata_test.cpp
index f02c4fc..eb978ca 100644
--- a/libs/ui/tests/BufferHubMetadata_test.cpp
+++ b/libs/ui/tests/BufferHubMetadata_test.cpp
@@ -51,7 +51,7 @@
 
     // Check if the newly allocated buffer is initialized in released state (i.e.
     // state equals to 0U).
-    EXPECT_TRUE(mh1->buffer_state.load() == 0U);
+    EXPECT_TRUE(mh1->bufferState.load() == 0U);
 
     EXPECT_TRUE(m2.isValid());
     BufferHubDefs::MetadataHeader* mh2 = m2.metadataHeader();
@@ -59,7 +59,7 @@
 
     // Check if the newly allocated buffer is initialized in released state (i.e.
     // state equals to 0U).
-    EXPECT_TRUE(mh2->buffer_state.load() == 0U);
+    EXPECT_TRUE(mh2->bufferState.load() == 0U);
 }
 
 TEST_F(BufferHubMetadataTest, MoveMetadataInvalidatesOldOne) {
diff --git a/libs/vr/libbufferhub/buffer_hub_base.cpp b/libs/vr/libbufferhub/buffer_hub_base.cpp
index b28d101..17930b4 100644
--- a/libs/vr/libbufferhub/buffer_hub_base.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_base.cpp
@@ -122,15 +122,15 @@
   // are mapped from shared memory as an atomic object. The std::atomic's
   // constructor will not be called so that the original value stored in the
   // memory region will be preserved.
-  buffer_state_ = &metadata_header_->buffer_state;
+  buffer_state_ = &metadata_header_->bufferState;
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, buffer_state=%" PRIx32 ".",
            id(), buffer_state_->load(std::memory_order_acquire));
-  fence_state_ = &metadata_header_->fence_state;
+  fence_state_ = &metadata_header_->fenceState;
   ALOGD_IF(TRACE,
            "BufferHubBase::ImportBuffer: id=%d, fence_state=%" PRIx32 ".", id(),
            fence_state_->load(std::memory_order_acquire));
-  active_clients_bit_mask_ = &metadata_header_->active_clients_bit_mask;
+  active_clients_bit_mask_ = &metadata_header_->activeClientsBitMask;
   ALOGD_IF(
       TRACE,
       "BufferHubBase::ImportBuffer: id=%d, active_clients_bit_mask=%" PRIx32
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
index fa39d08..8a490d9 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_base.h
@@ -97,8 +97,8 @@
   uint32_t usage() const { return buffer_.usage(); }
   uint32_t layer_count() const { return buffer_.layer_count(); }
 
-  uint64_t GetQueueIndex() const { return metadata_header_->queue_index; }
-  void SetQueueIndex(uint64_t index) { metadata_header_->queue_index = index; }
+  uint64_t GetQueueIndex() const { return metadata_header_->queueIndex; }
+  void SetQueueIndex(uint64_t index) { metadata_header_->queueIndex = index; }
 
  protected:
   explicit BufferHubBase(LocalChannelHandle channel);
diff --git a/services/bufferhub/BufferHubService.cpp b/services/bufferhub/BufferHubService.cpp
index ade08e7..7a3472f 100644
--- a/services/bufferhub/BufferHubService.cpp
+++ b/services/bufferhub/BufferHubService.cpp
@@ -241,8 +241,8 @@
 
         MetadataHeader* metadataHeader =
                 const_cast<BufferHubMetadata*>(&node->metadata())->metadataHeader();
-        const uint32_t state = metadataHeader->buffer_state.load(std::memory_order_acquire);
-        const uint64_t index = metadataHeader->queue_index;
+        const uint32_t state = metadataHeader->bufferState.load(std::memory_order_acquire);
+        const uint64_t index = metadataHeader->queueIndex;
 
         stream << std::right;
         stream << std::setw(6) << /*Id=*/node->id();
diff --git a/services/bufferhub/BufferNode.cpp b/services/bufferhub/BufferNode.cpp
index 1efb27e..04ca649 100644
--- a/services/bufferhub/BufferNode.cpp
+++ b/services/bufferhub/BufferNode.cpp
@@ -15,9 +15,9 @@
     // Using placement new here to reuse shared memory instead of new allocation
     // Initialize the atomic variables to zero.
     BufferHubDefs::MetadataHeader* metadataHeader = mMetadata.metadataHeader();
-    mBufferState = new (&metadataHeader->buffer_state) std::atomic<uint32_t>(0);
-    mFenceState = new (&metadataHeader->fence_state) std::atomic<uint32_t>(0);
-    mActiveClientsBitMask = new (&metadataHeader->active_clients_bit_mask) std::atomic<uint32_t>(0);
+    mBufferState = new (&metadataHeader->bufferState) std::atomic<uint32_t>(0);
+    mFenceState = new (&metadataHeader->fenceState) std::atomic<uint32_t>(0);
+    mActiveClientsBitMask = new (&metadataHeader->activeClientsBitMask) std::atomic<uint32_t>(0);
     // The C++ standard recommends (but does not require) that lock-free atomic operations are
     // also address-free, that is, suitable for communication between processes using shared
     // memory.
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index f84aa34..1a1ae21 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -4550,7 +4550,8 @@
             mPointerController->setButtonState(mCurrentRawState.buttonState);
             mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords,
                     mCurrentCookedState.cookedPointerData.idToIndex,
-                    mCurrentCookedState.cookedPointerData.touchingIdBits);
+                    mCurrentCookedState.cookedPointerData.touchingIdBits,
+                    mViewport.displayId);
         }
 
         if (!mCurrentMotionAborted) {
@@ -5314,7 +5315,8 @@
         if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
             mPointerController->setSpots(mPointerGesture.currentGestureCoords,
                      mPointerGesture.currentGestureIdToIndex,
-                     mPointerGesture.currentGestureIdBits);
+                     mPointerGesture.currentGestureIdBits,
+                     mPointerController->getDisplayId());
         }
     } else {
         mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index bc0f1f9..0ff28e4 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -94,7 +94,7 @@
      * pressed (not hovering).
      */
     virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
-            BitSet32 spotIdBits) = 0;
+            BitSet32 spotIdBits, int32_t displayId) = 0;
 
     /* Removes all spots. */
     virtual void clearSpots() = 0;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 84c5ad6..fbacb9b 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -103,6 +103,10 @@
         return mDisplayId;
     }
 
+    const std::map<int32_t, std::vector<int32_t>>& getSpots() {
+        return mSpotsByDisplay;
+    }
+
 private:
     virtual bool getBounds(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const {
         *outMinX = mMinX;
@@ -130,11 +134,22 @@
     virtual void setPresentation(Presentation) {
     }
 
-    virtual void setSpots(const PointerCoords*, const uint32_t*, BitSet32) {
+    virtual void setSpots(const PointerCoords*, const uint32_t*, BitSet32 spotIdBits,
+            int32_t displayId) {
+        std::vector<int32_t> newSpots;
+        // Add spots for fingers that are down.
+        for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) {
+            uint32_t id = idBits.clearFirstMarkedBit();
+            newSpots.push_back(id);
+        }
+
+        mSpotsByDisplay[displayId] = newSpots;
     }
 
     virtual void clearSpots() {
     }
+
+    std::map<int32_t, std::vector<int32_t>> mSpotsByDisplay;
 };
 
 
@@ -228,6 +243,10 @@
         mConfig.pointerCapture = enabled;
     }
 
+    void setShowTouches(bool enabled) {
+        mConfig.showTouches = enabled;
+    }
+
 private:
     DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
             int32_t orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort,
@@ -6315,4 +6334,85 @@
     ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
 }
 
+TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
+    // Setup the first touch screen device.
+    MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+    prepareAxes(POSITION | ID | SLOT);
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    addMapperAndConfigure(mapper);
+
+    // Create the second touch screen device, and enable multi fingers.
+    const std::string USB2 = "USB2";
+    const int32_t SECOND_DEVICE_ID = 2;
+    InputDeviceIdentifier identifier;
+    identifier.name = DEVICE_NAME;
+    identifier.location = USB2;
+    InputDevice* device2 = new InputDevice(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION,
+            DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
+    mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_TRACKING_ID, RAW_ID_MIN, RAW_ID_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_SLOT, RAW_SLOT_MIN, RAW_SLOT_MAX,
+            0 /*flat*/, 0 /*fuzz*/);
+    mFakeEventHub->setAbsoluteAxisValue(SECOND_DEVICE_ID, ABS_MT_SLOT, 0 /*value*/);
+    mFakeEventHub->addConfigurationProperty(SECOND_DEVICE_ID, String8("touch.deviceType"),
+            String8("touchScreen"));
+
+    // Setup the second touch screen device.
+    MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2);
+    device2->addMapper(mapper2);
+    device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
+    device2->reset(ARBITRARY_TIME);
+
+    // Setup PointerController.
+    sp<FakePointerController> fakePointerController = new FakePointerController();
+    mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
+    mFakePolicy->setPointerController(SECOND_DEVICE_ID, fakePointerController);
+
+    // Setup policy for associated displays and show touches.
+    const uint8_t hdmi1 = 0;
+    const uint8_t hdmi2 = 1;
+    mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
+    mFakePolicy->addInputPortAssociation(USB2, hdmi2);
+    mFakePolicy->setShowTouches(true);
+
+    // Create displays.
+    prepareDisplay(DISPLAY_ORIENTATION_0, hdmi1);
+    prepareSecondaryDisplay(ViewportType::VIEWPORT_EXTERNAL, hdmi2);
+
+    // Default device will reconfigure above, need additional reconfiguration for another device.
+    device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+            InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+    // Two fingers down at default display.
+    int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
+    processPosition(mapper, x1, y1);
+    processId(mapper, 1);
+    processSlot(mapper, 1);
+    processPosition(mapper, x2, y2);
+    processId(mapper, 2);
+    processSync(mapper);
+
+    std::map<int32_t, std::vector<int32_t>>::const_iterator iter =
+            fakePointerController->getSpots().find(DISPLAY_ID);
+    ASSERT_TRUE(iter != fakePointerController->getSpots().end());
+    ASSERT_EQ(size_t(2), iter->second.size());
+
+    // Two fingers down at second display.
+    processPosition(mapper2, x1, y1);
+    processId(mapper2, 1);
+    processSlot(mapper2, 1);
+    processPosition(mapper2, x2, y2);
+    processId(mapper2, 2);
+    processSync(mapper2);
+
+    iter = fakePointerController->getSpots().find(SECONDARY_DISPLAY_ID);
+    ASSERT_TRUE(iter != fakePointerController->getSpots().end());
+    ASSERT_EQ(size_t(2), iter->second.size());
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 89eee6b..b4952aa 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -24,8 +24,12 @@
 #include <mutex>
 
 #include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <cutils/compiler.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
@@ -66,11 +70,10 @@
 BufferLayer::~BufferLayer() {
     mFlinger->deleteTextureAsync(mTextureName);
 
-    if (!getBE().mHwcLayers.empty()) {
+    if (destroyAllHwcLayersPlusChildren()) {
         ALOGE("Found stale hardware composer layers when destroying "
               "surface flinger layer %s",
               mName.string());
-        destroyAllHwcLayersPlusChildren();
     }
 
     mFlinger->mTimeStats->onDestroy(getSequence());
@@ -91,7 +94,7 @@
 bool BufferLayer::isOpaque(const Layer::State& s) const {
     // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+    if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
         return false;
     }
 
@@ -102,7 +105,7 @@
 
 bool BufferLayer::isVisible() const {
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
-            (mActiveBuffer != nullptr || getBE().compositionInfo.hwc.sidebandStream != nullptr);
+            (mActiveBuffer != nullptr || mSidebandStream != nullptr);
 }
 
 bool BufferLayer::isFixedSize() const {
@@ -171,7 +174,8 @@
         layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
         layer.source.buffer.isY410BT2020 = isHdrY410();
         // TODO: we could be more subtle with isFixedSize()
-        const bool useFiltering = needsFiltering() || renderArea.needsFiltering() || isFixedSize();
+        const bool useFiltering = needsFiltering(renderArea.getDisplayDevice()) ||
+                renderArea.needsFiltering() || isFixedSize();
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
@@ -237,26 +241,31 @@
     // pixel format is HDR Y410 masquerading as RGBA_1010102
     return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
             getDrawingApi() == NATIVE_WINDOW_API_MEDIA &&
-            getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
+            mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
 }
 
-void BufferLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
-                                  const Rect& viewport, int32_t supportedPerFrameMetadata) {
-    RETURN_IF_NO_HWC_LAYER(displayId);
+void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
+                                  const ui::Transform& transform, const Rect& viewport,
+                                  int32_t supportedPerFrameMetadata) {
+    RETURN_IF_NO_HWC_LAYER(displayDevice);
 
     // Apply this display's projection's viewport to the visible region
     // before giving it to the HWC HAL.
     Region visible = transform.transform(visibleRegion.intersect(viewport));
 
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+    const auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
+
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
     auto error = hwcLayer->setVisibleRegion(visible);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
         visible.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.visibleRegion = visible;
+    outputLayer->editState().visibleRegion = visible;
+
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
 
     error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
     if (error != HWC2::Error::None) {
@@ -264,29 +273,29 @@
               to_string(error).c_str(), static_cast<int32_t>(error));
         surfaceDamageRegion.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
+    layerCompositionState.surfaceDamage = surfaceDamageRegion;
 
     // Sideband layers
-    if (getBE().compositionInfo.hwc.sidebandStream.get()) {
-        setCompositionType(displayId, HWC2::Composition::Sideband);
+    if (layerCompositionState.sidebandStream.get()) {
+        setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::SIDEBAND);
         ALOGV("[%s] Requesting Sideband composition", mName.string());
-        error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
+        error = hwcLayer->setSidebandStream(layerCompositionState.sidebandStream->handle());
         if (error != HWC2::Error::None) {
             ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
-                  getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
+                  layerCompositionState.sidebandStream->handle(), to_string(error).c_str(),
                   static_cast<int32_t>(error));
         }
-        getBE().compositionInfo.compositionType = HWC2::Composition::Sideband;
+        layerCompositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
         return;
     }
 
     // Device or Cursor layers
     if (mPotentialCursor) {
         ALOGV("[%s] Requesting Cursor composition", mName.string());
-        setCompositionType(displayId, HWC2::Composition::Cursor);
+        setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CURSOR);
     } else {
         ALOGV("[%s] Requesting Device composition", mName.string());
-        setCompositionType(displayId, HWC2::Composition::Device);
+        setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
     }
 
     ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
@@ -308,12 +317,11 @@
         ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
                 to_string(error).c_str(), static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
-    getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
-    getBE().compositionInfo.hwc.supportedPerFrameMetadata = supportedPerFrameMetadata;
-    getBE().compositionInfo.hwc.colorTransform = getColorTransform();
+    layerCompositionState.dataspace = mCurrentDataSpace;
+    layerCompositionState.colorTransform = getColorTransform();
+    layerCompositionState.hdrMetadata = metadata;
 
-    setHwcLayerBuffer(displayId);
+    setHwcLayerBuffer(displayDevice);
 }
 
 bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -372,8 +380,7 @@
     return true;
 }
 
-bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                              const sp<Fence>& releaseFence) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
     ATRACE_CALL();
 
     bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
@@ -412,7 +419,7 @@
         return false;
     }
 
-    status_t err = updateTexImage(recomputeVisibleRegions, latchTime, releaseFence);
+    status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
     if (err != NO_ERROR) {
         return false;
     }
@@ -605,9 +612,21 @@
     return true;
 }
 
-bool BufferLayer::needsFiltering() const {
-    const auto displayFrame = getBE().compositionInfo.hwc.displayFrame;
-    const auto sourceCrop = getBE().compositionInfo.hwc.sourceCrop;
+bool BufferLayer::needsFiltering(const sp<const DisplayDevice>& displayDevice) const {
+    // If we are not capturing based on the state of a known display device, we
+    // only return mNeedsFiltering
+    if (displayDevice == nullptr) {
+        return mNeedsFiltering;
+    }
+
+    const auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (outputLayer == nullptr) {
+        return mNeedsFiltering;
+    }
+
+    const auto& compositionState = outputLayer->getState();
+    const auto displayFrame = compositionState.displayFrame;
+    const auto sourceCrop = compositionState.sourceCrop;
     return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
             sourceCrop.getWidth() != displayFrame.getWidth();
 }
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 0f8a350..e3b10fc 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -80,8 +80,8 @@
 
     bool isHdrY410() const override;
 
-    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
-                         int32_t supportedPerFrameMetadata) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
+                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
 
     bool onPreComposition(nsecs_t refreshStartTime) override;
     bool onPostComposition(const std::optional<DisplayId>& displayId,
@@ -93,11 +93,7 @@
     // the visible regions need to be recomputed (this is a fairly heavy
     // operation, so this should be set only if needed). Typically this is used
     // to figure out if the content or size of a surface has changed.
-    // If there was a GL composition step rendering the previous frame, then
-    // releaseFence will be populated with a native fence that fires when
-    // composition has completed.
-    bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                     const sp<Fence>& releaseFence) override;
+    bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
 
     bool isBufferLatched() const override { return mRefreshPending; }
 
@@ -142,13 +138,12 @@
     virtual void setFilteringEnabled(bool enabled) = 0;
 
     virtual status_t bindTextureImage() = 0;
-    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                    const sp<Fence>& flushFence) = 0;
+    virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
 
     virtual status_t updateActiveBuffer() = 0;
     virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
 
-    virtual void setHwcLayerBuffer(DisplayId displayId) = 0;
+    virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) = 0;
 
 protected:
     // Loads the corresponding system property once per process
@@ -177,7 +172,7 @@
 
 private:
     // Returns true if this layer requires filtering
-    bool needsFiltering() const;
+    bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
 
     uint64_t getHeadFrameNumber() const;
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 7ed8184..6866e5c 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -100,8 +100,7 @@
 
 status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
                                              bool* autoRefresh, bool* queuedBuffer,
-                                             uint64_t maxFrameNumber,
-                                             const sp<Fence>& releaseFence) {
+                                             uint64_t maxFrameNumber) {
     ATRACE_CALL();
     BLC_LOGV("updateTexImage");
     Mutex::Autolock lock(mMutex);
@@ -146,7 +145,7 @@
     }
 
     // Release the previous buffer.
-    err = updateAndReleaseLocked(item, &mPendingRelease, releaseFence);
+    err = updateAndReleaseLocked(item, &mPendingRelease);
     if (err != NO_ERROR) {
         return err;
     }
@@ -224,25 +223,11 @@
 }
 
 status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
-                                                     PendingRelease* pendingRelease,
-                                                     const sp<Fence>& releaseFence) {
+                                                     PendingRelease* pendingRelease) {
     status_t err = NO_ERROR;
 
     int slot = item.mSlot;
 
-    // Do whatever sync ops we need to do before releasing the old slot.
-    if (slot != mCurrentTexture) {
-        err = syncForReleaseLocked(releaseFence);
-        if (err != NO_ERROR) {
-            // Release the buffer we just acquired.  It's not safe to
-            // release the old buffer, so instead we just drop the new frame.
-            // As we are still under lock since acquireBuffer, it is safe to
-            // release by slot.
-            releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
-            return err;
-        }
-    }
-
     BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
              mCurrentTextureBuffer != nullptr ? mCurrentTextureBuffer->handle : 0, slot,
              mSlots[slot].mGraphicBuffer->handle);
@@ -298,30 +283,6 @@
     return mRE.bindExternalTextureBuffer(mTexName, mCurrentTextureBuffer, mCurrentFence, false);
 }
 
-status_t BufferLayerConsumer::syncForReleaseLocked(const sp<Fence>& releaseFence) {
-    BLC_LOGV("syncForReleaseLocked");
-
-    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (mRE.useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
-            // TODO(alecmouri): fail further upstream if the fence is invalid
-            if (!releaseFence->isValid()) {
-                BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
-                return UNKNOWN_ERROR;
-            }
-            status_t err =
-                    addReleaseFenceLocked(mCurrentTexture, mCurrentTextureBuffer, releaseFence);
-            if (err != OK) {
-                BLC_LOGE("syncForReleaseLocked: error adding release fence: "
-                         "%s (%d)",
-                         strerror(-err), err);
-                return err;
-            }
-        }
-    }
-
-    return OK;
-}
-
 void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
     Mutex::Autolock lock(mMutex);
     memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index e2ef399..e2a6d2e 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -92,8 +92,7 @@
     // used to reject the newly acquired buffer.  It also does not bind the
     // RenderEngine texture until bindTextureImage is called.
     status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime,
-                            bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber,
-                            const sp<Fence>& releaseFence);
+                            bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber);
 
     // See BufferLayerConsumer::bindTextureImageLocked().
     status_t bindTextureImage();
@@ -212,8 +211,7 @@
     // completion of the method will instead be returned to the caller, so that
     // it may call releaseBufferLocked itself later.
     status_t updateAndReleaseLocked(const BufferItem& item,
-                                    PendingRelease* pendingRelease = nullptr,
-                                    const sp<Fence>& releaseFence = Fence::NO_FENCE);
+                                    PendingRelease* pendingRelease = nullptr);
 
     // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
     // If the bind succeeds, this calls doFenceWait.
@@ -244,12 +242,6 @@
     // access the current texture buffer.
     status_t doFenceWaitLocked() const;
 
-    // syncForReleaseLocked performs the synchronization needed to release the
-    // current slot from RenderEngine.  If needed it will set the current
-    // slot's fence to guard against a producer accessing the buffer before
-    // the outstanding accesses have completed.
-    status_t syncForReleaseLocked(const sp<Fence>& releaseFence);
-
     // The default consumer usage flags that BufferLayerConsumer always sets on its
     // BufferQueue instance; these will be OR:d with any additional flags passed
     // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 0313c32..5fe8067 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -14,13 +14,18 @@
  * limitations under the License.
  */
 
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <system/window.h>
+
 #include "BufferQueueLayer.h"
 #include "LayerRejecter.h"
 
 #include "TimeStats/TimeStats.h"
 
-#include <system/window.h>
-
 namespace android {
 
 BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {}
@@ -195,8 +200,9 @@
     if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
         // mSidebandStreamChanged was changed to false
         // replicated in LayerBE until FE/BE is ready to be synchronized
-        getBE().compositionInfo.hwc.sidebandStream = mConsumer->getSidebandStream();
-        if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+        auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+        layerCompositionState.sidebandStream = mConsumer->getSidebandStream();
+        if (layerCompositionState.sidebandStream != nullptr) {
             setTransactionFlags(eTransactionNeeded);
             mFlinger->setTransactionFlags(eTraversalNeeded);
         }
@@ -219,8 +225,7 @@
     return mConsumer->bindTextureImage();
 }
 
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                                          const sp<Fence>& releaseFence) {
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
     // This boolean is used to make sure that SurfaceFlinger's shadow copy
     // of the buffer queue isn't modified when the buffer queue is returning
     // BufferItem's that weren't actually queued. This can happen in shared
@@ -231,10 +236,14 @@
                     getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
                     getTransformToDisplayInverse(), mFreezeGeometryUpdates);
 
-    const nsecs_t expectedPresentTime = mFlinger->mUseScheduler
+    nsecs_t expectedPresentTime = mFlinger->mUseScheduler
             ? mFlinger->mScheduler->expectedPresentTime()
             : mFlinger->mPrimaryDispSync->expectedPresentTime();
 
+    if (isRemovedFromCurrentState()) {
+        expectedPresentTime = 0;
+    }
+
     // updateTexImage() below might drop the some buffers at the head of the queue if there is a
     // buffer behind them which is timely to be presented. However this buffer may not be signaled
     // yet. The code below makes sure that this wouldn't happen by setting maxFrameNumber to the
@@ -253,9 +262,9 @@
     }
     const uint64_t maxFrameNumberToAcquire =
             std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber);
-    status_t updateResult =
-            mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh, &queuedBuffer,
-                                      maxFrameNumberToAcquire, releaseFence);
+
+    status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &mAutoRefresh,
+                                                      &queuedBuffer, maxFrameNumberToAcquire);
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
@@ -325,8 +334,9 @@
 status_t BufferQueueLayer::updateActiveBuffer() {
     // update the active buffer
     mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
-    getBE().compositionInfo.mBuffer = mActiveBuffer;
-    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.buffer = mActiveBuffer;
+    layerCompositionState.bufferSlot = mActiveBufferSlot;
 
     if (mActiveBuffer == nullptr) {
         // this can only happen if the very first buffer was rejected.
@@ -350,24 +360,28 @@
     return NO_ERROR;
 }
 
-void BufferQueueLayer::setHwcLayerBuffer(DisplayId displayId) {
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    LOG_FATAL_IF(!outputLayer->getState.hwc);
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
+    (*outputLayer->editState().hwc)
+            .hwcBufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
     if (error != HWC2::Error::None) {
-        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
-              getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
-              static_cast<int32_t>(error));
+        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
+              to_string(error).c_str(), static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
-    getBE().compositionInfo.mBuffer = mActiveBuffer;
-    getBE().compositionInfo.hwc.fence = acquireFence;
+
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.bufferSlot = mActiveBufferSlot;
+    layerCompositionState.buffer = mActiveBuffer;
+    layerCompositionState.acquireFence = acquireFence;
 }
 
 // -----------------------------------------------------------------------
@@ -377,7 +391,7 @@
 void BufferQueueLayer::fakeVsync() {
     mRefreshPending = false;
     bool ignored = false;
-    latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+    latchBuffer(ignored, systemTime());
     usleep(16000);
     releasePendingBuffer(systemTime());
 }
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index d392a69..fbb8c14 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -91,13 +91,12 @@
     void setFilteringEnabled(bool enabled) override;
 
     status_t bindTextureImage() override;
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                            const sp<Fence>& releaseFence) override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
 
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
 
-    void setHwcLayerBuffer(DisplayId displayId) override;
+    void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) override;
 
     // -----------------------------------------------------------------------
     // Interface implementation for BufferLayerConsumer::ContentsChangedListener
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 2d6da76..e48c41e 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -19,15 +19,19 @@
 #define LOG_TAG "BufferStateLayer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include "BufferStateLayer.h"
-#include "ColorLayer.h"
+#include <limits>
 
-#include "TimeStats/TimeStats.h"
-
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <private/gui/SyncFeatures.h>
 #include <renderengine/Image.h>
 
-#include <limits>
+#include "BufferStateLayer.h"
+#include "ColorLayer.h"
+#include "TimeStats/TimeStats.h"
 
 namespace android {
 
@@ -438,9 +442,10 @@
     if (mSidebandStreamChanged.exchange(false)) {
         const State& s(getDrawingState());
         // mSidebandStreamChanged was true
-        // replicated in LayerBE until FE/BE is ready to be synchronized
-        getBE().compositionInfo.hwc.sidebandStream = s.sidebandStream;
-        if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+        LOG_ALWAYS_FATAL_IF(!getCompositionLayer());
+        mSidebandStream = s.sidebandStream;
+        getCompositionLayer()->editState().frontEnd.sidebandStream = mSidebandStream;
+        if (mSidebandStream != nullptr) {
             setTransactionFlags(eTransactionNeeded);
             mFlinger->setTransactionFlags(eTraversalNeeded);
         }
@@ -468,8 +473,7 @@
     return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence, false);
 }
 
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
-                                          const sp<Fence>& releaseFence) {
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
     const State& s(getDrawingState());
 
     if (!s.buffer) {
@@ -511,59 +515,7 @@
         handle->latchTime = latchTime;
     }
 
-    // Handle sync fences
-    if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
-        // TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
-        if (!releaseFence->isValid()) {
-            mFlinger->mTimeStats->onDestroy(layerID);
-            return UNKNOWN_ERROR;
-        }
-
-        // Check status of fences first because merging is expensive.
-        // Merging an invalid fence with any other fence results in an
-        // invalid fence.
-        auto currentStatus = s.acquireFence->getStatus();
-        if (currentStatus == Fence::Status::Invalid) {
-            ALOGE("Existing fence has invalid state");
-            mFlinger->mTimeStats->onDestroy(layerID);
-            return BAD_VALUE;
-        }
-
-        auto incomingStatus = releaseFence->getStatus();
-        if (incomingStatus == Fence::Status::Invalid) {
-            ALOGE("New fence has invalid state");
-            mDrawingState.acquireFence = releaseFence;
-            mFlinger->mTimeStats->onDestroy(layerID);
-            return BAD_VALUE;
-        }
-
-        // If both fences are signaled or both are unsignaled, we need to merge
-        // them to get an accurate timestamp.
-        if (currentStatus == incomingStatus) {
-            char fenceName[32] = {};
-            snprintf(fenceName, 32, "%.28s:%d", mName.string(), mFrameNumber);
-            sp<Fence> mergedFence =
-                    Fence::merge(fenceName, mDrawingState.acquireFence, releaseFence);
-            if (!mergedFence.get()) {
-                ALOGE("failed to merge release fences");
-                // synchronization is broken, the best we can do is hope fences
-                // signal in order so the new fence will act like a union
-                mDrawingState.acquireFence = releaseFence;
-                mFlinger->mTimeStats->onDestroy(layerID);
-                return BAD_VALUE;
-            }
-            mDrawingState.acquireFence = mergedFence;
-        } else if (incomingStatus == Fence::Status::Unsignaled) {
-            // If one fence has signaled and the other hasn't, the unsignaled
-            // fence will approximately correspond with the correct timestamp.
-            // There's a small race if both fences signal at about the same time
-            // and their statuses are retrieved with unfortunate timing. However,
-            // by this point, they will have both signaled and only the timestamp
-            // will be slightly off; any dependencies after this point will
-            // already have been met.
-            mDrawingState.acquireFence = releaseFence;
-        }
-    } else {
+    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
         // Bind the new buffer to the GL texture.
         //
         // Older devices require the "implicit" synchronization provided
@@ -594,8 +546,9 @@
 
     mActiveBuffer = s.buffer;
     mActiveBufferFence = s.acquireFence;
-    getBE().compositionInfo.mBuffer = mActiveBuffer;
-    getBE().compositionInfo.mBufferSlot = 0;
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.buffer = mActiveBuffer;
+    layerCompositionState.bufferSlot = 0;
 
     return NO_ERROR;
 }
@@ -611,9 +564,10 @@
     return NO_ERROR;
 }
 
-void BufferStateLayer::setHwcLayerBuffer(DisplayId displayId) {
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
 
     const State& s(getDrawingState());
 
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 3320c5b..0b03f49 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -125,13 +125,12 @@
     void setFilteringEnabled(bool enabled) override;
 
     status_t bindTextureImage() override;
-    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
-                            const sp<Fence>& releaseFence) override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
 
     status_t updateActiveBuffer() override;
     status_t updateFrameNumber(nsecs_t latchTime) override;
 
-    void setHwcLayerBuffer(DisplayId displayId) override;
+    void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
 
 private:
     void onFirstRef() override;
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 0ca3759..e54b460 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -17,7 +17,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 
-#include <binder/PermissionCache.h>
 #include <binder/IPCThreadState.h>
 
 #include <private/android_filesystem_config.h>
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index d82ff0e..9ea0a46 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -23,8 +23,12 @@
 #include <sys/types.h>
 
 #include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Display.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <renderengine/RenderEngine.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/Errors.h>
@@ -73,30 +77,36 @@
     return true;
 }
 
-void ColorLayer::setPerFrameData(DisplayId displayId, const ui::Transform& transform,
-                                 const Rect& viewport, int32_t /* supportedPerFrameMetadata */) {
-    RETURN_IF_NO_HWC_LAYER(displayId);
+void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
+                                 const ui::Transform& transform, const Rect& viewport,
+                                 int32_t /* supportedPerFrameMetadata */) {
+    RETURN_IF_NO_HWC_LAYER(display);
 
     Region visible = transform.transform(visibleRegion.intersect(viewport));
 
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
+
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
+
     auto error = hwcLayer->setVisibleRegion(visible);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
         visible.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.visibleRegion = visible;
+    outputLayer->editState().visibleRegion = visible;
 
-    setCompositionType(displayId, HWC2::Composition::SolidColor);
+    setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
 
     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));
     }
-    getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
+
+    auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+    layerCompositionState.dataspace = mCurrentDataSpace;
 
     half4 color = getColor();
     error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
@@ -106,9 +116,9 @@
         ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
               static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.color = { static_cast<uint8_t>(std::round(255.0f * color.r)),
-                                      static_cast<uint8_t>(std::round(255.0f * color.g)),
-                                      static_cast<uint8_t>(std::round(255.0f * color.b)), 255 };
+    layerCompositionState.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
+                                   static_cast<uint8_t>(std::round(255.0f * color.g)),
+                                   static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
 
     // Clear out the transform, because it doesn't make sense absent a source buffer
     error = hwcLayer->setTransform(HWC2::Transform::None);
@@ -116,14 +126,14 @@
         ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
               static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.transform = HWC2::Transform::None;
+    outputLayer->editState().bufferTransform = static_cast<Hwc2::Transform>(0);
 
     error = hwcLayer->setColorTransform(getColorTransform());
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
                 to_string(error).c_str(), static_cast<int32_t>(error));
     }
-    getBE().compositionInfo.hwc.colorTransform = getColorTransform();
+    layerCompositionState.colorTransform = getColorTransform();
 
     error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
     if (error != HWC2::Error::None) {
@@ -131,7 +141,7 @@
               to_string(error).c_str(), static_cast<int32_t>(error));
         surfaceDamageRegion.dump(LOG_TAG);
     }
-    getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
+    layerCompositionState.surfaceDamage = surfaceDamageRegion;
 }
 
 std::shared_ptr<compositionengine::Layer> ColorLayer::getCompositionLayer() const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index ed4c2d8..df0adac 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -35,8 +35,8 @@
 
     bool setColor(const half3& color) override;
 
-    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
-                         int32_t supportedPerFrameMetadata) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
+                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
 
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
 
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ce6b06c..f5376a5 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -5,6 +5,7 @@
         "-DLOG_TAG=\"CompositionEngine\"",
     ],
     shared_libs: [
+        "android.frameworks.vr.composer@1.0",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
@@ -28,6 +29,9 @@
         "libtrace_proto",
     ],
     header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
         "libsurfaceflinger_headers",
     ],
 }
@@ -43,9 +47,11 @@
         "src/DumpHelpers.cpp",
         "src/HwcBufferCache.cpp",
         "src/Layer.cpp",
+        "src/LayerCompositionState.cpp",
         "src/Output.cpp",
         "src/OutputCompositionState.cpp",
         "src/OutputLayer.cpp",
+        "src/OutputLayerCompositionState.cpp",
         "src/RenderSurface.cpp",
     ],
     local_include_dirs: ["include"],
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
index 29a7dea..8cb9203 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cstdint>
+#include <string>
 
 #include <utils/StrongPointer.h>
 
@@ -29,6 +30,10 @@
 class Display;
 class LayerFE;
 
+namespace impl {
+struct LayerCompositionState;
+} // namespace impl
+
 /**
  * A layer contains the output-independent composition state for a front-end
  * Layer
@@ -40,6 +45,21 @@
     // Gets the front-end interface for this layer.  Can return nullptr if the
     // front-end layer no longer exists.
     virtual sp<LayerFE> getLayerFE() const = 0;
+
+    using CompositionState = impl::LayerCompositionState;
+
+    // Gets the raw composition state data for the layer
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual const CompositionState& getState() const = 0;
+
+    // Allows mutable access to the raw composition state data for the layer.
+    // This is meant to be used by the various functions that are part of the
+    // composition process.
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual CompositionState& editState() = 0;
+
+    // Debugging
+    virtual void dump(std::string& result) const = 0;
 };
 
 } // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
new file mode 100644
index 0000000..2201bdd
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2019 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 <cstdint>
+
+#include <gui/BufferQueue.h>
+#include <gui/HdrMetadata.h>
+#include <math/mat4.h>
+#include <ui/FloatRect.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+#include "DisplayHardware/ComposerHal.h"
+
+namespace android::compositionengine {
+
+/*
+ * Used by LayerFE::getCompositionState
+ */
+struct LayerFECompositionState {
+    /*
+     * Presentation
+     */
+
+    // The blend mode for this layer
+    Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID};
+
+    // The alpha value for this layer
+    float alpha{1.f};
+
+    /*
+     * Extra metadata
+     */
+
+    // The type for this layer
+    int type{0};
+
+    // The appId for this layer
+    int appId{0};
+
+    /*
+     * Per-frame content
+     */
+
+    // The type of composition for this layer
+    Hwc2::IComposerClient::Composition compositionType{Hwc2::IComposerClient::Composition::INVALID};
+
+    // The buffer and related state
+    sp<GraphicBuffer> buffer;
+    int bufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
+    sp<Fence> acquireFence;
+    Region surfaceDamage;
+
+    // The handle to use for a sideband stream for this layer
+    sp<NativeHandle> sidebandStream;
+
+    // The color for this layer
+    Hwc2::IComposerClient::Color color;
+
+    /*
+     * Per-frame presentation state
+     */
+
+    // The dataspace for this layer
+    ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
+    // The metadata for this layer
+    HdrMetadata hdrMetadata;
+
+    // The color transform
+    mat4 colorTransform;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index 4b8ef38..48cb581 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -16,14 +16,22 @@
 
 #pragma once
 
+#include <string>
+
 #include <utils/StrongPointer.h>
 
-namespace android::compositionengine {
+namespace android {
+
+namespace compositionengine {
 
 class Output;
 class Layer;
 class LayerFE;
 
+namespace impl {
+struct OutputLayerCompositionState;
+} // namespace impl
+
 /**
  * An output layer contains the output-dependent composition state for a layer
  */
@@ -39,6 +47,22 @@
 
     // Gets the front-end layer interface this output layer represents
     virtual LayerFE& getLayerFE() const = 0;
+
+    using CompositionState = compositionengine::impl::OutputLayerCompositionState;
+
+    // Gets the raw composition state data for the layer
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual const CompositionState& getState() const = 0;
+
+    // Allows mutable access to the raw composition state data for the layer.
+    // This is meant to be used by the various functions that are part of the
+    // composition process.
+    // TODO(lpique): Make this protected once it is only internally called.
+    virtual CompositionState& editState() = 0;
+
+    // Debugging
+    virtual void dump(std::string& result) const = 0;
 };
 
-} // namespace android::compositionengine
+} // namespace compositionengine
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index ddeb730..2009380 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -29,8 +29,6 @@
 
 class GraphicBuffer;
 
-struct CompositionInfo;
-
 namespace compositionengine {
 
 /**
@@ -70,7 +68,7 @@
     virtual status_t beginFrame(bool mustRecompose) = 0;
 
     // Prepares the frame for rendering
-    virtual status_t prepareFrame(std::vector<CompositionInfo>& compositionData) = 0;
+    virtual status_t prepareFrame() = 0;
 
     // Allocates a buffer as scratch space for GPU composition
     virtual sp<GraphicBuffer> dequeueBuffer() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
index 631351b..3e56b21 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
@@ -19,6 +19,7 @@
 #include <memory>
 
 #include <compositionengine/Layer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 
@@ -40,9 +41,16 @@
 
     sp<LayerFE> getLayerFE() const override;
 
+    const LayerCompositionState& getState() const override;
+    LayerCompositionState& editState() override;
+
+    void dump(std::string& result) const override;
+
 private:
     const compositionengine::CompositionEngine& mCompositionEngine;
     const wp<LayerFE> mLayerFE;
+
+    LayerCompositionState mState;
 };
 
 std::shared_ptr<compositionengine::Layer> createLayer(const compositionengine::CompositionEngine&,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
new file mode 100644
index 0000000..67bea4b
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <string>
+
+#include <compositionengine/LayerFECompositionState.h>
+#include <renderengine/Mesh.h>
+
+namespace android {
+
+namespace compositionengine::impl {
+
+struct LayerCompositionState {
+    /*
+     * State intended to be set by LayerFE::getCompositionState
+     */
+
+    LayerFECompositionState frontEnd;
+
+    /*
+     * RE state
+     */
+
+    renderengine::Mesh reMesh{renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2};
+
+    // Debugging
+    void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index f3d0258..5798540 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -17,8 +17,10 @@
 #pragma once
 
 #include <memory>
+#include <string>
 
 #include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 
 namespace android::compositionengine::impl {
 
@@ -32,10 +34,17 @@
     compositionengine::Layer& getLayer() const override;
     compositionengine::LayerFE& getLayerFE() const override;
 
+    const OutputLayerCompositionState& getState() const override;
+    OutputLayerCompositionState& editState() override;
+
+    void dump(std::string& result) const override;
+
 private:
     const compositionengine::Output& mOutput;
     std::shared_ptr<compositionengine::Layer> mLayer;
     sp<compositionengine::LayerFE> mLayerFE;
+
+    OutputLayerCompositionState mState;
 };
 
 std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
new file mode 100644
index 0000000..b78e9e0
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <optional>
+#include <string>
+
+#include <compositionengine/impl/HwcBufferCache.h>
+#include <renderengine/Mesh.h>
+#include <ui/FloatRect.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+#include "DisplayHardware/ComposerHal.h"
+
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
+namespace android {
+
+class HWComposer;
+
+namespace compositionengine::impl {
+
+struct OutputLayerCompositionState {
+    // The region of this layer which is visible on this output
+    Region visibleRegion;
+
+    // If true, client composition will be used on this output
+    bool forceClientComposition{false};
+
+    // If true, when doing client composition, the target may need to be cleared
+    bool clearClientTarget{false};
+
+    // The display frame for this layer on this output
+    Rect displayFrame;
+
+    // The source crop for this layer on this output
+    FloatRect sourceCrop;
+
+    // The buffer transform to use for this layer o on this output.
+    Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)};
+
+    // The Z order index of this layer on this output
+    uint32_t z;
+
+    /*
+     * HWC state
+     */
+
+    struct Hwc {
+        explicit Hwc(std::shared_ptr<HWC2::Layer> hwcLayer) : hwcLayer(hwcLayer) {}
+
+        // The HWC Layer backing this layer
+        std::shared_ptr<HWC2::Layer> hwcLayer;
+
+        // The HWC composition type for this layer
+        Hwc2::IComposerClient::Composition hwcCompositionType{
+                Hwc2::IComposerClient::Composition::INVALID};
+
+        // The buffer cache for this layer. This is used to lower the
+        // cost of sending reused buffers to the HWC.
+        HwcBufferCache hwcBufferCache;
+    };
+
+    // The HWC state is optional, and is only set up if there is any potential
+    // HWC acceleration possible.
+    std::optional<Hwc> hwc;
+
+    // Debugging
+    void dump(std::string& result) const;
+};
+
+} // namespace compositionengine::impl
+} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 2f0fceb..58b13ed 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -51,7 +51,7 @@
     void setDisplaySize(const ui::Size&) override;
     void setProtected(bool useProtected) override;
     status_t beginFrame(bool mustRecompose) override;
-    status_t prepareFrame(std::vector<CompositionInfo>& compositionData) override;
+    status_t prepareFrame() override;
     sp<GraphicBuffer> dequeueBuffer() override;
     void queueBuffer(base::unique_fd&& readyFence) override;
     void onPresentDisplayCompleted() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
index a7cc08e..cce3b97 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
@@ -18,6 +18,7 @@
 
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <gmock/gmock.h>
 
 namespace android::compositionengine::mock {
@@ -28,6 +29,11 @@
     virtual ~Layer();
 
     MOCK_CONST_METHOD0(getLayerFE, sp<LayerFE>());
+
+    MOCK_CONST_METHOD0(getState, const CompositionState&());
+    MOCK_METHOD0(editState, CompositionState&());
+
+    MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index f5e5026..6bd61ee 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -20,6 +20,7 @@
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/Output.h>
 #include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <gmock/gmock.h>
 
 namespace android::compositionengine::mock {
@@ -32,6 +33,11 @@
     MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&());
     MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&());
     MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&());
+
+    MOCK_CONST_METHOD0(getState, const impl::OutputLayerCompositionState&());
+    MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
+
+    MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
 } // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index e9ff330..8442bef 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -20,7 +20,6 @@
 #include <gmock/gmock.h>
 #include <ui/GraphicBuffer.h>
 
-#include "LayerBE.h"
 
 namespace android::compositionengine::mock {
 
@@ -37,7 +36,7 @@
     MOCK_METHOD1(setProtected, void(bool));
     MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
     MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
-    MOCK_METHOD1(prepareFrame, status_t(std::vector<CompositionInfo>& compositionData));
+    MOCK_METHOD0(prepareFrame, status_t());
     MOCK_METHOD0(dequeueBuffer, sp<GraphicBuffer>());
     MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
     MOCK_METHOD0(onPresentDisplayCompleted, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
index aaa758e..109e9f8 100644
--- a/services/surfaceflinger/CompositionEngine/src/Layer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/LayerCreationArgs.h>
 #include <compositionengine/LayerFE.h>
@@ -42,5 +43,18 @@
     return mLayerFE.promote();
 }
 
+const LayerCompositionState& Layer::getState() const {
+    return mState;
+}
+
+LayerCompositionState& Layer::editState() {
+    return mState;
+}
+
+void Layer::dump(std::string& out) const {
+    android::base::StringAppendF(&out, "     Layer %p\n", this);
+    mState.dump(out);
+}
+
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
new file mode 100644
index 0000000..517b641
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+
+namespace android::compositionengine::impl {
+
+namespace {
+
+using android::compositionengine::impl::dumpVal;
+
+void dumpVal(std::string& out, const char* name, Hwc2::IComposerClient::Color value) {
+    using android::base::StringAppendF;
+    StringAppendF(&out, "%s=[%d %d %d] ", name, value.r, value.g, value.b);
+}
+
+void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) {
+    out.append("      ");
+    dumpVal(out, "blend", toString(state.blendMode), state.blendMode);
+    dumpVal(out, "alpha", state.alpha);
+
+    out.append("\n      ");
+    dumpVal(out, "type", state.type);
+    dumpVal(out, "appId", state.appId);
+
+    dumpVal(out, "composition type", toString(state.compositionType), state.compositionType);
+
+    out.append("\n      buffer: ");
+    dumpVal(out, "buffer", state.buffer.get());
+    dumpVal(out, "slot", state.bufferSlot);
+
+    out.append("\n      ");
+    dumpVal(out, "sideband stream", state.sidebandStream.get());
+
+    out.append("\n      ");
+    dumpVal(out, "color", state.color);
+
+    out.append("\n      ");
+    dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
+    dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
+    dumpVal(out, "colorTransform", state.colorTransform);
+
+    out.append("\n");
+}
+
+} // namespace
+
+void LayerCompositionState::dump(std::string& out) const {
+    out.append("      frontend:\n");
+    dumpFrontEnd(out, frontEnd);
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e103ebe..f97add4 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -146,6 +146,14 @@
     } else {
         out.append("    No render surface!\n");
     }
+
+    out.append("\n   %d Layers", mOutputLayersOrderedByZ.size());
+    for (const auto& outputLayer : mOutputLayersOrderedByZ) {
+        if (!outputLayer) {
+            continue;
+        }
+        outputLayer->dump(out);
+    }
 }
 
 compositionengine::DisplayColorProfile* Output::getDisplayColorProfile() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index e95f3a6..78c1403 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android-base/stringprintf.h>
 #include <compositionengine/Layer.h>
 #include <compositionengine/LayerFE.h>
 #include <compositionengine/Output.h>
@@ -48,5 +49,20 @@
     return *mLayerFE;
 }
 
+const OutputLayerCompositionState& OutputLayer::getState() const {
+    return mState;
+}
+
+OutputLayerCompositionState& OutputLayer::editState() {
+    return mState;
+}
+
+void OutputLayer::dump(std::string& out) const {
+    using android::base::StringAppendF;
+
+    StringAppendF(&out, "     Output Layer %p\n", this);
+    mState.dump(out);
+}
+
 } // namespace impl
 } // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
new file mode 100644
index 0000000..10f27b8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+
+#include "DisplayHardware/HWC2.h"
+
+namespace android::compositionengine::impl {
+
+namespace {
+
+void dumpHwc(const OutputLayerCompositionState::Hwc& hwc, std::string& out) {
+    out.append("\n      hwc: ");
+
+    if (hwc.hwcLayer == nullptr) {
+        out.append("No layer ");
+    } else {
+        dumpHex(out, "layer", hwc.hwcLayer->getId());
+    }
+
+    dumpVal(out, "composition", toString(hwc.hwcCompositionType), hwc.hwcCompositionType);
+}
+
+} // namespace
+
+void OutputLayerCompositionState::dump(std::string& out) const {
+    out.append("      ");
+    dumpVal(out, "visibleRegion", visibleRegion);
+
+    out.append("      ");
+    dumpVal(out, "forceClientComposition", forceClientComposition);
+    dumpVal(out, "clearClientTarget", clearClientTarget);
+    dumpVal(out, "displayFrame", displayFrame);
+    dumpVal(out, "sourceCrop", sourceCrop);
+    dumpVal(out, "bufferTransform%", toString(bufferTransform), bufferTransform);
+    dumpVal(out, "z-index", z);
+
+    if (hwc) {
+        dumpHwc(*hwc, out);
+    }
+
+    out.append("\n");
+}
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 3f841d2..ebb1bc2 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -99,11 +99,11 @@
     return mDisplaySurface->beginFrame(mustRecompose);
 }
 
-status_t RenderSurface::prepareFrame(std::vector<CompositionInfo>& compositionData) {
+status_t RenderSurface::prepareFrame() {
     auto& hwc = mCompositionEngine.getHwComposer();
     const auto id = mDisplay.getId();
     if (id) {
-        status_t error = hwc.prepare(*id, compositionData);
+        status_t error = hwc.prepare(*id, mDisplay);
         if (error != NO_ERROR) {
             return error;
         }
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index ece412f..885cdd4 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -16,10 +16,9 @@
 
 #pragma once
 
+#include <compositionengine/Output.h>
 #include <gmock/gmock.h>
 
-#include "LayerBE.h"
-
 #include "DisplayHardware/HWComposer.h"
 
 namespace android {
@@ -41,7 +40,7 @@
                  std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
     MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
     MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
-    MOCK_METHOD2(prepare, status_t(DisplayId, std::vector<CompositionInfo>&));
+    MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
     MOCK_METHOD5(setClientTarget,
                  status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
                           ui::Dataspace));
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index c56d92a..0a7c462 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -22,6 +22,7 @@
 #include <compositionengine/mock/CompositionEngine.h>
 #include <compositionengine/mock/Display.h>
 #include <compositionengine/mock/DisplaySurface.h>
+#include <compositionengine/mock/OutputLayer.h>
 #include <gtest/gtest.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <system/window.h>
@@ -284,64 +285,66 @@
  * RenderSurface::prepareFrame()
  */
 
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data)))
+TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
             .WillOnce(Return(INVALID_OPERATION));
 
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+}
+
+TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(INVALID_OPERATION));
+
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
-    std::vector<CompositionInfo> data;
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
             .WillOnce(Return(INVALID_OPERATION));
 
-    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame(data));
+    EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
 }
 
 TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
-    std::vector<CompositionInfo> data;
-
-    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(data))).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
+            .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
     EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
 
     EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
             .WillOnce(Return(NO_ERROR));
 
-    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame(data));
+    EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
 }
 
 /* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 941b4ad..22c40d7 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -39,6 +39,7 @@
     return !isHiddenByPolicy();
 }
 
-void ContainerLayer::setPerFrameData(DisplayId, const ui::Transform&, const Rect&, int32_t) {}
+void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
+                                     const Rect&, int32_t) {}
 
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index fec82d7..c69997d 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -33,8 +33,8 @@
 
     bool canReceiveInput() const override;
 
-    void setPerFrameData(DisplayId displayId, const ui::Transform& transform, const Rect& viewport,
-                         int32_t supportedPerFrameMetadata) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
+                         const Rect& viewport, int32_t supportedPerFrameMetadata) override;
 
     bool isCreatedFromMainThread() const override { return true; }
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 9674f0d..a827c47 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -266,6 +266,7 @@
     int getHeight() const override { return mDevice->getHeight(); }
     int getWidth() const override { return mDevice->getWidth(); }
     bool isSecure() const override { return mDevice->isSecure(); }
+    const sp<const DisplayDevice> getDisplayDevice() const override { return mDevice; }
 
     bool needsFiltering() const override {
         // check if the projection from the logical display to the physical
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 5b4d347..3b9e0e6 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -20,13 +20,14 @@
 #define LOG_TAG "HWComposer"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <utils/Errors.h>
-#include <utils/Trace.h>
-
+#include <compositionengine/Output.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <log/log.h>
 #include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
-
-#include <log/log.h>
+#include <utils/Errors.h>
+#include <utils/Trace.h>
 
 #include "HWComposer.h"
 #include "HWC2.h"
@@ -398,7 +399,7 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) {
+status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Output& output) {
     ATRACE_CALL();
 
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -462,47 +463,42 @@
 
     displayData.hasClientComposition = false;
     displayData.hasDeviceComposition = false;
-    for (auto& compositionInfo : compositionData) {
-        auto hwcLayer = compositionInfo.hwc.hwcLayer;
+    for (auto& outputLayer : output.getOutputLayersOrderedByZ()) {
+        auto& state = outputLayer->editState();
+        LOG_FATAL_IF(!state.hwc.);
+        auto hwcLayer = (*state.hwc).hwcLayer;
 
-        if (changedTypes.count(&*hwcLayer) != 0) {
-            // We pass false so we only update our state and don't call back
-            // into the HWC device
-            validateChange(compositionInfo.compositionType,
-                    changedTypes[&*hwcLayer]);
-            compositionInfo.compositionType = changedTypes[&*hwcLayer];
-            compositionInfo.layer->mLayer->setCompositionType(displayId,
-                                                              compositionInfo.compositionType,
-                                                              false);
+        if (auto it = changedTypes.find(hwcLayer.get()); it != changedTypes.end()) {
+            auto newCompositionType = it->second;
+            validateChange(static_cast<HWC2::Composition>((*state.hwc).hwcCompositionType),
+                           newCompositionType);
+            (*state.hwc).hwcCompositionType =
+                    static_cast<Hwc2::IComposerClient::Composition>(newCompositionType);
         }
 
-        switch (compositionInfo.compositionType) {
-            case HWC2::Composition::Client:
+        switch ((*state.hwc).hwcCompositionType) {
+            case Hwc2::IComposerClient::Composition::CLIENT:
                 displayData.hasClientComposition = true;
                 break;
-            case HWC2::Composition::Device:
-            case HWC2::Composition::SolidColor:
-            case HWC2::Composition::Cursor:
-            case HWC2::Composition::Sideband:
+            case Hwc2::IComposerClient::Composition::DEVICE:
+            case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+            case Hwc2::IComposerClient::Composition::CURSOR:
+            case Hwc2::IComposerClient::Composition::SIDEBAND:
                 displayData.hasDeviceComposition = true;
                 break;
             default:
                 break;
         }
 
-        if (layerRequests.count(&*hwcLayer) != 0 &&
-                layerRequests[&*hwcLayer] ==
-                        HWC2::LayerRequest::ClearClientTarget) {
-            compositionInfo.hwc.clearClientTarget = true;
-            compositionInfo.layer->mLayer->setClearClientTarget(displayId, true);
-        } else {
-            if (layerRequests.count(&*hwcLayer) != 0) {
+        state.clearClientTarget = false;
+        if (auto it = layerRequests.find(hwcLayer.get()); it != layerRequests.end()) {
+            auto request = it->second;
+            if (request == HWC2::LayerRequest::ClearClientTarget) {
+                state.clearClientTarget = true;
+            } else {
                 LOG_DISPLAY_ERROR(displayId,
-                                  ("Unknown layer request " + to_string(layerRequests[&*hwcLayer]))
-                                          .c_str());
+                                  ("Unknown layer request " + to_string(request)).c_str());
             }
-            compositionInfo.hwc.clearClientTarget = false;
-            compositionInfo.layer->mLayer->setClearClientTarget(displayId, false);
         }
     }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f42f860..ca59a26 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -45,6 +45,10 @@
 class Composer;
 } // namespace Hwc2
 
+namespace compositionengine {
+class Output;
+} // namespace compositionengine
+
 class HWComposer {
 public:
     virtual ~HWComposer();
@@ -68,8 +72,7 @@
     virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
 
     // Asks the HAL what it can do
-    virtual status_t prepare(DisplayId displayId,
-                             std::vector<CompositionInfo>& compositionData) = 0;
+    virtual status_t prepare(DisplayId displayId, const compositionengine::Output&) = 0;
 
     virtual status_t setClientTarget(DisplayId displayId, uint32_t slot,
                                      const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
@@ -205,7 +208,7 @@
     void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override;
 
     // Asks the HAL what it can do
-    status_t prepare(DisplayId displayId, std::vector<CompositionInfo>& compositionData) override;
+    status_t prepare(DisplayId displayId, const compositionengine::Output&) override;
 
     status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
                              const sp<GraphicBuffer>& target, ui::Dataspace dataspace) override;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 51e1f00..7b8ad71 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -24,44 +24,42 @@
 #include <stdlib.h>
 #include <sys/types.h>
 #include <algorithm>
+#include <mutex>
 
 #include <android-base/stringprintf.h>
-
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <cutils/compiler.h>
 #include <cutils/native_handle.h>
 #include <cutils/properties.h>
-
+#include <gui/BufferItem.h>
+#include <gui/LayerDebugInfo.h>
+#include <gui/Surface.h>
+#include <renderengine/RenderEngine.h>
+#include <ui/DebugUtils.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/PixelFormat.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <utils/NativeHandle.h>
 #include <utils/StopWatch.h>
 #include <utils/Trace.h>
 
-#include <ui/DebugUtils.h>
-#include <ui/GraphicBuffer.h>
-#include <ui/PixelFormat.h>
-
-#include <gui/BufferItem.h>
-#include <gui/LayerDebugInfo.h>
-#include <gui/Surface.h>
-
 #include "BufferLayer.h"
 #include "ColorLayer.h"
 #include "Colorizer.h"
 #include "DisplayDevice.h"
+#include "DisplayHardware/HWComposer.h"
 #include "Layer.h"
+#include "LayerProtoHelper.h"
 #include "LayerRejecter.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
-
-#include "DisplayHardware/HWComposer.h"
 #include "TimeStats/TimeStats.h"
 
-#include <renderengine/RenderEngine.h>
-
-#include <mutex>
-#include "LayerProtoHelper.h"
-
 #define DEBUG_RESIZE 0
 
 namespace android {
@@ -211,9 +209,16 @@
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
-bool Layer::createHwcLayer(HWComposer* hwc, DisplayId displayId) {
-    LOG_ALWAYS_FATAL_IF(hasHwcLayer(displayId), "Already have a layer for display %s",
-                        to_string(displayId).c_str());
+bool Layer::createHwcLayer(HWComposer* hwc, const sp<DisplayDevice>& displayDevice) {
+    LOG_ALWAYS_FATAL_IF(!displayDevice->getId());
+    auto displayId = *displayDevice->getId();
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    LOG_ALWAYS_FATAL_IF(!outputLayer);
+
+    LOG_ALWAYS_FATAL_IF(outputLayer->getState().hwc.has_value(),
+                        "Already have a layer for display %s",
+                        displayDevice->getDisplayName().c_str());
+
     auto layer = std::shared_ptr<HWC2::Layer>(
             hwc->createLayer(displayId),
             [hwc, displayId](HWC2::Layer* layer) {
@@ -221,42 +226,56 @@
     if (!layer) {
         return false;
     }
-    LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[displayId];
-    hwcInfo.hwc = hwc;
-    hwcInfo.layer = layer;
-    layer->setLayerDestroyedListener(
-            [this, displayId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(displayId); });
+    auto& state = outputLayer->editState();
+    state.hwc.emplace(layer);
     return true;
 }
 
-bool Layer::destroyHwcLayer(DisplayId displayId) {
-    if (!hasHwcLayer(displayId)) {
+bool Layer::destroyHwcLayer(const sp<DisplayDevice>& displayDevice) {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (outputLayer == nullptr) {
         return false;
     }
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, "Attempt to destroy null layer");
-    LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer");
-    hwcInfo.layer = nullptr;
-
-    return true;
+    auto& state = outputLayer->editState();
+    bool result = state.hwc.has_value();
+    state.hwc.reset();
+    return result;
 }
 
-void Layer::destroyHwcLayersForAllDisplays() {
-    size_t numLayers = getBE().mHwcLayers.size();
-    for (size_t i = 0; i < numLayers; ++i) {
-        LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.empty(), "destroyAllHwcLayers failed");
-        destroyHwcLayer(getBE().mHwcLayers.begin()->first);
+bool Layer::destroyHwcLayersForAllDisplays() {
+    bool destroyedAnyLayers = false;
+
+    for (const auto& [token, displayDevice] : mFlinger->mDisplays) {
+        if (destroyHwcLayer(displayDevice)) {
+            destroyedAnyLayers = true;
+        }
     }
+
+    return destroyedAnyLayers;
 }
 
-void Layer::destroyAllHwcLayersPlusChildren() {
-    destroyHwcLayersForAllDisplays();
-    LOG_ALWAYS_FATAL_IF(!getBE().mHwcLayers.empty(),
-                        "All hardware composer layers should have been destroyed");
+bool Layer::destroyAllHwcLayersPlusChildren() {
+    bool result = destroyHwcLayersForAllDisplays();
 
     for (const sp<Layer>& child : mDrawingChildren) {
-        child->destroyAllHwcLayersPlusChildren();
+        result |= child->destroyAllHwcLayersPlusChildren();
     }
+
+    return result;
+}
+
+bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().hwc && (*outputLayer->getState().hwc).hwcLayer != nullptr;
+}
+
+HWC2::Layer* Layer::getHwcLayer(const sp<const DisplayDevice>& displayDevice) {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (!outputLayer || !outputLayer->getState().hwc) {
+        return nullptr;
+    }
+    return (*outputLayer->getState().hwc).hwcLayer.get();
 }
 
 Rect Layer::getContentCrop() const {
@@ -266,9 +285,9 @@
     if (!mCurrentCrop.isEmpty()) {
         // if the buffer crop is defined, we use that
         crop = mCurrentCrop;
-    } else if (getBE().compositionInfo.mBuffer != nullptr) {
+    } else if (mActiveBuffer != nullptr) {
         // otherwise we use the whole buffer
-        crop = getBE().compositionInfo.mBuffer->getBounds();
+        crop = mActiveBuffer->getBounds();
     } else {
         // if we don't have a buffer yet, we use an empty/invalid crop
         crop.makeInvalid();
@@ -322,18 +341,18 @@
     // for in the transform. We need to mirror this scaling to child surfaces
     // or we will break the contract where WM can treat child surfaces as
     // pixels in the parent surface.
-    if (!isFixedSize() || !getBE().compositionInfo.mBuffer) {
+    if (!isFixedSize() || !mActiveBuffer) {
         return mEffectiveTransform;
     }
 
     int bufferWidth;
     int bufferHeight;
     if ((mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
-        bufferWidth = getBE().compositionInfo.mBuffer->getWidth();
-        bufferHeight = getBE().compositionInfo.mBuffer->getHeight();
+        bufferWidth = mActiveBuffer->getWidth();
+        bufferHeight = mActiveBuffer->getHeight();
     } else {
-        bufferHeight = getBE().compositionInfo.mBuffer->getWidth();
-        bufferWidth = getBE().compositionInfo.mBuffer->getHeight();
+        bufferHeight = mActiveBuffer->getWidth();
+        bufferWidth = mActiveBuffer->getHeight();
     }
     float sx = getActiveWidth(getDrawingState()) / static_cast<float>(bufferWidth);
     float sy = getActiveHeight(getDrawingState()) / static_cast<float>(bufferHeight);
@@ -421,7 +440,8 @@
     win.top -= roundedCornersCrop.top;
     win.bottom -= roundedCornersCrop.top;
 
-    renderengine::Mesh::VertexArray<vec2> cropCoords(getBE().mMesh.getCropCoordArray<vec2>());
+    renderengine::Mesh::VertexArray<vec2> cropCoords(
+            getCompositionLayer()->editState().reMesh.getCropCoordArray<vec2>());
     cropCoords[0] = vec2(win.left, win.top);
     cropCoords[1] = vec2(win.left, win.top + win.getHeight());
     cropCoords[2] = vec2(win.right, win.top + win.getHeight());
@@ -494,19 +514,27 @@
 }
 
 void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
-    const auto displayId = display->getId();
-    LOG_ALWAYS_FATAL_IF(!displayId);
-    RETURN_IF_NO_HWC_LAYER(*displayId);
-    auto& hwcInfo = getBE().mHwcLayers[*displayId];
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    LOG_FATAL_IF(!outputLayer->getState().hwc);
+    auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
 
-    // enable this layer
-    hwcInfo.forceClientComposition = false;
-
-    if (isSecure() && !display->isSecure()) {
-        hwcInfo.forceClientComposition = true;
+    if (!hasHwcLayer(display)) {
+        ALOGE("[%s] failed to setGeometry: no HWC layer found (%s)", mName.string(),
+              display->getDebugName().c_str());
+        return;
     }
 
-    auto& hwcLayer = hwcInfo.layer;
+    LOG_FATAL_IF(!getCompositionLayer());
+    auto& commonCompositionState = getCompositionLayer()->editState().frontEnd;
+    auto& compositionState = outputLayer->editState();
+
+    // enable this layer
+    compositionState.forceClientComposition = false;
+
+    if (isSecure() && !display->isSecure()) {
+        compositionState.forceClientComposition = true;
+    }
 
     // this gives us only the "orientation" component of the transform
     const State& s(getDrawingState());
@@ -522,7 +550,7 @@
              " %s (%d)",
              mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(),
              static_cast<int32_t>(error));
-    getBE().compositionInfo.hwc.blendMode = blendMode;
+    commonCompositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
 
     // apply the layer's transform, followed by the display's global transform
     // here we're guaranteed that the layer's transform preserves rects
@@ -567,9 +595,8 @@
               transformedFrame.left, transformedFrame.top, transformedFrame.right,
               transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
     } else {
-        hwcInfo.displayFrame = transformedFrame;
+        compositionState.displayFrame = transformedFrame;
     }
-    getBE().compositionInfo.hwc.displayFrame = transformedFrame;
 
     FloatRect sourceCrop = computeCrop(display);
     error = hwcLayer->setSourceCrop(sourceCrop);
@@ -579,9 +606,8 @@
               mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom,
               to_string(error).c_str(), static_cast<int32_t>(error));
     } else {
-        hwcInfo.sourceCrop = sourceCrop;
+        compositionState.sourceCrop = sourceCrop;
     }
-    getBE().compositionInfo.hwc.sourceCrop = sourceCrop;
 
     float alpha = static_cast<float>(getAlpha());
     error = hwcLayer->setPlaneAlpha(alpha);
@@ -589,12 +615,12 @@
              "[%s] Failed to set plane alpha %.3f: "
              "%s (%d)",
              mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
-    getBE().compositionInfo.hwc.alpha = alpha;
+    commonCompositionState.alpha = alpha;
 
     error = hwcLayer->setZOrder(z);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
              to_string(error).c_str(), static_cast<int32_t>(error));
-    getBE().compositionInfo.hwc.z = z;
+    compositionState.z = z;
 
     int type = s.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
     int appId = s.metadata.getInt32(METADATA_OWNER_UID, 0);
@@ -613,8 +639,8 @@
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
              static_cast<int32_t>(error));
 
-    getBE().compositionInfo.hwc.type = type;
-    getBE().compositionInfo.hwc.appId = appId;
+    commonCompositionState.type = type;
+    commonCompositionState.appId = appId;
 
     /*
      * Transformations are applied in this order:
@@ -651,35 +677,39 @@
     const uint32_t orientation = transform.getOrientation();
     if (orientation & ui::Transform::ROT_INVALID) {
         // we can only handle simple transformation
-        hwcInfo.forceClientComposition = true;
-        getBE().mHwcLayers[*displayId].compositionType = HWC2::Composition::Client;
+        compositionState.forceClientComposition = true;
+        (*compositionState.hwc).hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
-        hwcInfo.transform = transform;
         auto error = hwcLayer->setTransform(transform);
         ALOGE_IF(error != HWC2::Error::None,
                  "[%s] Failed to set transform %s: "
                  "%s (%d)",
                  mName.string(), to_string(transform).c_str(), to_string(error).c_str(),
                  static_cast<int32_t>(error));
-        getBE().compositionInfo.hwc.transform = transform;
+        compositionState.bufferTransform = static_cast<Hwc2::Transform>(transform);
     }
 }
 
-void Layer::forceClientComposition(DisplayId displayId) {
-    RETURN_IF_NO_HWC_LAYER(displayId);
-    getBE().mHwcLayers[displayId].forceClientComposition = true;
+void Layer::forceClientComposition(const sp<DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    outputLayer->editState().forceClientComposition = true;
 }
 
-bool Layer::getForceClientComposition(DisplayId displayId) {
-    RETURN_IF_NO_HWC_LAYER(displayId, false);
-    return getBE().mHwcLayers[displayId].forceClientComposition;
+bool Layer::getForceClientComposition(const sp<DisplayDevice>& display) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().forceClientComposition;
 }
 
 void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
-    const auto displayId = display->getId();
-    LOG_ALWAYS_FATAL_IF(!displayId);
-    if (!hasHwcLayer(*displayId) || getCompositionType(displayId) != HWC2::Composition::Cursor) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+
+    if (!outputLayer->getState().hwc ||
+        (*outputLayer->getState().hwc).hwcCompositionType !=
+                Hwc2::IComposerClient::Composition::CURSOR) {
         return;
     }
 
@@ -697,8 +727,7 @@
     auto position = displayTransform.transform(frame);
 
     auto error =
-            getBE().mHwcLayers[*displayId].layer->setCursorPosition(position.left, position.top);
-
+            (*outputLayer->getState().hwc).hwcLayer->setCursorPosition(position.left, position.top);
     ALOGE_IF(error != HWC2::Error::None,
              "[%s] Failed to set cursor position "
              "to (%d, %d): %s (%d)",
@@ -760,65 +789,50 @@
 void Layer::clearWithOpenGL(const RenderArea& renderArea, float red, float green, float blue,
                             float alpha) const {
     auto& engine(mFlinger->getRenderEngine());
-    computeGeometry(renderArea, getBE().mMesh, false);
+    computeGeometry(renderArea, getCompositionLayer()->editState().reMesh, false);
     engine.setupFillWithColor(red, green, blue, alpha);
-    engine.drawMesh(getBE().mMesh);
+    engine.drawMesh(getCompositionLayer()->getState().reMesh);
 }
 
 void Layer::clearWithOpenGL(const RenderArea& renderArea) const {
     clearWithOpenGL(renderArea, 0, 0, 0, 0);
 }
 
-void Layer::setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc) {
-    if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("setCompositionType called without a valid HWC layer");
-        return;
-    }
-    auto& hwcInfo = getBE().mHwcLayers[displayId];
-    auto& hwcLayer = hwcInfo.layer;
-    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", (hwcLayer)->getId(), to_string(type).c_str(),
-          static_cast<int>(callIntoHwc));
-    if (hwcInfo.compositionType != type) {
+void Layer::setCompositionType(const sp<const DisplayDevice>& display,
+                               Hwc2::IComposerClient::Composition type) {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    LOG_FATAL_IF(!outputLayer->getState().hwc);
+    auto& compositionState = outputLayer->editState();
+
+    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", ((*compositionState.hwc).hwcLayer)->getId(),
+          toString(type).c_str(), 1);
+    if ((*compositionState.hwc).hwcCompositionType != type) {
         ALOGV("    actually setting");
-        hwcInfo.compositionType = type;
-        if (callIntoHwc) {
-            auto error = (hwcLayer)->setCompositionType(type);
-            ALOGE_IF(error != HWC2::Error::None,
-                     "[%s] Failed to set "
-                     "composition type %s: %s (%d)",
-                     mName.string(), to_string(type).c_str(), to_string(error).c_str(),
-                     static_cast<int32_t>(error));
-        }
+        (*compositionState.hwc).hwcCompositionType = type;
+
+        auto error = (*compositionState.hwc)
+                             .hwcLayer->setCompositionType(static_cast<HWC2::Composition>(type));
+        ALOGE_IF(error != HWC2::Error::None,
+                 "[%s] Failed to set "
+                 "composition type %s: %s (%d)",
+                 mName.string(), toString(type).c_str(), to_string(error).c_str(),
+                 static_cast<int32_t>(error));
     }
 }
 
-HWC2::Composition Layer::getCompositionType(const std::optional<DisplayId>& displayId) const {
-    if (!displayId) {
-        // If we're querying the composition type for a display that does not
-        // have a HWC counterpart, then it will always be Client
-        return HWC2::Composition::Client;
-    }
-    if (getBE().mHwcLayers.count(*displayId) == 0) {
-        ALOGE("getCompositionType called with an invalid HWC layer");
-        return HWC2::Composition::Invalid;
-    }
-    return getBE().mHwcLayers.at(*displayId).compositionType;
+Hwc2::IComposerClient::Composition Layer::getCompositionType(
+        const sp<const DisplayDevice>& display) const {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().hwc ? (*outputLayer->getState().hwc).hwcCompositionType
+                                       : Hwc2::IComposerClient::Composition::CLIENT;
 }
 
-void Layer::setClearClientTarget(DisplayId displayId, bool clear) {
-    if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("setClearClientTarget called without a valid HWC layer");
-        return;
-    }
-    getBE().mHwcLayers[displayId].clearClientTarget = clear;
-}
-
-bool Layer::getClearClientTarget(DisplayId displayId) const {
-    if (getBE().mHwcLayers.count(displayId) == 0) {
-        ALOGE("getClearClientTarget called without a valid HWC layer");
-        return false;
-    }
-    return getBE().mHwcLayers.at(displayId).clearClientTarget;
+bool Layer::getClearClientTarget(const sp<const DisplayDevice>& display) const {
+    const auto outputLayer = findOutputLayerForDisplay(display);
+    LOG_FATAL_IF(!outputLayer);
+    return outputLayer->getState().clearClientTarget;
 }
 
 bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
@@ -1037,9 +1051,9 @@
     const bool resizePending =
             ((stateToCommit->requested_legacy.w != stateToCommit->active_legacy.w) ||
              (stateToCommit->requested_legacy.h != stateToCommit->active_legacy.h)) &&
-            (getBE().compositionInfo.mBuffer != nullptr);
+            (mActiveBuffer != nullptr);
     if (!isFixedSize()) {
-        if (resizePending && getBE().compositionInfo.hwc.sidebandStream == nullptr) {
+        if (resizePending && mSidebandStream == nullptr) {
             flags |= eDontUpdateGeometryState;
         }
     }
@@ -1535,8 +1549,9 @@
     result.append("-----------------------------\n");
 }
 
-void Layer::miniDump(std::string& result, DisplayId displayId) const {
-    if (!hasHwcLayer(displayId)) {
+void Layer::miniDump(std::string& result, const sp<DisplayDevice>& displayDevice) const {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (!outputLayer) {
         return;
     }
 
@@ -1554,26 +1569,24 @@
     StringAppendF(&result, " %s\n", name.c_str());
 
     const State& layerState(getDrawingState());
-    const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(displayId);
+    const auto& compositionState = outputLayer->getState();
+
     if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
         StringAppendF(&result, "  rel %6d | ", layerState.z);
     } else {
         StringAppendF(&result, "  %10d | ", layerState.z);
     }
-    StringAppendF(&result, "%10s | ", to_string(getCompositionType(displayId)).c_str());
-    StringAppendF(&result, "%10s | ", to_string(hwcInfo.transform).c_str());
-    const Rect& frame = hwcInfo.displayFrame;
+    StringAppendF(&result, "%10s | ", toString(getCompositionType(displayDevice)).c_str());
+    StringAppendF(&result, "%10s | ",
+                  toString(getCompositionLayer() ? compositionState.bufferTransform
+                                                 : static_cast<Hwc2::Transform>(0))
+                          .c_str());
+    const Rect& frame = compositionState.displayFrame;
     StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
-    const FloatRect& crop = hwcInfo.sourceCrop;
+    const FloatRect& crop = compositionState.sourceCrop;
     StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right,
                   crop.bottom);
 
-    result.append("- - - - - - - - - - - - - - - -\n");
-
-    std::string compositionInfoStr;
-    getBE().compositionInfo.dump(compositionInfoStr, "compositionInfo");
-    result.append(compositionInfoStr);
-
     result.append("- - - - - - - - - - - - - - - -");
     result.append("- - - - - - - - - - - - - - - -");
     result.append("- - - - - - - - - - - - - - -\n");
@@ -2132,8 +2145,7 @@
         layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
     }
 
-    // XXX getBE().compositionInfo.mBuffer is not protected
-    auto buffer = getBE().compositionInfo.mBuffer;
+    auto buffer = mActiveBuffer;
     if (buffer != nullptr) {
         LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
         LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
@@ -2164,25 +2176,29 @@
     LayerProtoHelper::writeToProto(mBounds, layerInfo->mutable_bounds());
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, DisplayId displayId) {
-    if (!hasHwcLayer(displayId)) {
+void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice) {
+    auto outputLayer = findOutputLayerForDisplay(displayDevice);
+    if (!outputLayer) {
         return;
     }
 
     writeToProto(layerInfo, LayerVector::StateSet::Drawing);
 
-    const auto& hwcInfo = getBE().mHwcLayers.at(displayId);
+    const auto& compositionState = outputLayer->getState();
 
-    const Rect& frame = hwcInfo.displayFrame;
+    const Rect& frame = compositionState.displayFrame;
     LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
 
-    const FloatRect& crop = hwcInfo.sourceCrop;
+    const FloatRect& crop = compositionState.sourceCrop;
     LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
 
-    const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+    const int32_t transform =
+            getCompositionLayer() ? static_cast<int32_t>(compositionState.bufferTransform) : 0;
     layerInfo->set_hwc_transform(transform);
 
-    const int32_t compositionType = static_cast<int32_t>(hwcInfo.compositionType);
+    const int32_t compositionType =
+            static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
+                                                      : Hwc2::IComposerClient::Composition::CLIENT);
     layerInfo->set_hwc_composition_type(compositionType);
 
     if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
@@ -2249,6 +2265,11 @@
     return isVisible();
 }
 
+compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
+        const sp<const DisplayDevice>& display) const {
+    return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionLayer().get());
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9241e71..36885db 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -51,6 +51,7 @@
 #include "SurfaceFlinger.h"
 #include "TransactionCompletedThread.h"
 
+#include "DisplayHardware/ComposerHal.h"
 #include "DisplayHardware/HWComposer.h"
 #include "RenderArea.h"
 
@@ -70,6 +71,7 @@
 
 namespace compositionengine {
 class Layer;
+class OutputLayer;
 }
 
 namespace impl {
@@ -419,7 +421,7 @@
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
-    void writeToProto(LayerProto* layerInfo, DisplayId displayId);
+    void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice);
 
     virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
     virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -443,17 +445,19 @@
     virtual bool isHdrY410() const { return false; }
 
     void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
-    void forceClientComposition(DisplayId displayId);
-    bool getForceClientComposition(DisplayId displayId);
-    virtual void setPerFrameData(DisplayId displayId, const ui::Transform& transform,
-                                 const Rect& viewport, int32_t supportedPerFrameMetadata) = 0;
+    void forceClientComposition(const sp<DisplayDevice>& display);
+    bool getForceClientComposition(const sp<DisplayDevice>& display);
+    virtual void setPerFrameData(const sp<const DisplayDevice>& display,
+                                 const ui::Transform& transform, const Rect& viewport,
+                                 int32_t supportedPerFrameMetadata) = 0;
 
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
-    void setCompositionType(DisplayId displayId, HWC2::Composition type, bool callIntoHwc = true);
-    HWC2::Composition getCompositionType(const std::optional<DisplayId>& displayId) const;
-    void setClearClientTarget(DisplayId displayId, bool clear);
-    bool getClearClientTarget(DisplayId displayId) const;
+    void setCompositionType(const sp<const DisplayDevice>& display,
+                            Hwc2::IComposerClient::Composition type);
+    Hwc2::IComposerClient::Composition getCompositionType(
+            const sp<const DisplayDevice>& display) const;
+    bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
     void updateCursorPosition(const sp<const DisplayDevice>& display);
 
     /*
@@ -530,8 +534,7 @@
      * operation, so this should be set only if needed). Typically this is used
      * to figure out if the content or size of a surface has changed.
      */
-    virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
-                             const sp<Fence>& /*releaseFence*/) {
+    virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
         return {};
     }
 
@@ -567,27 +570,13 @@
 
     // -----------------------------------------------------------------------
 
-    bool createHwcLayer(HWComposer* hwc, DisplayId displayId);
-    bool destroyHwcLayer(DisplayId displayId);
-    void destroyHwcLayersForAllDisplays();
-    void destroyAllHwcLayersPlusChildren();
+    bool createHwcLayer(HWComposer* hwc, const sp<DisplayDevice>& display);
+    bool destroyHwcLayer(const sp<DisplayDevice>& display);
+    bool destroyHwcLayersForAllDisplays();
+    bool destroyAllHwcLayersPlusChildren();
 
-    bool hasHwcLayer(DisplayId displayId) const { return getBE().mHwcLayers.count(displayId) > 0; }
-
-    HWC2::Layer* getHwcLayer(DisplayId displayId) {
-        if (!hasHwcLayer(displayId)) {
-            return nullptr;
-        }
-        return getBE().mHwcLayers[displayId].layer.get();
-    }
-
-    bool setHwcLayer(DisplayId displayId) {
-        if (!hasHwcLayer(displayId)) {
-            return false;
-        }
-        getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[displayId].layer;
-        return true;
-    }
+    bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
+    HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
 
     // -----------------------------------------------------------------------
     void clearWithOpenGL(const RenderArea& renderArea) const;
@@ -600,7 +589,7 @@
 
     /* always call base class first */
     static void miniDumpHeader(std::string& result);
-    void miniDump(std::string& result, DisplayId displayId) const;
+    void miniDump(std::string& result, const sp<DisplayDevice>& display) const;
     void dumpFrameStats(std::string& result) const;
     void dumpFrameEvents(std::string& result);
     void clearFrameStats();
@@ -676,6 +665,9 @@
         return parentBounds;
     }
 
+    compositionengine::OutputLayer* findOutputLayerForDisplay(
+            const sp<const DisplayDevice>& display) const;
+
 protected:
     // constant
     sp<SurfaceFlinger> mFlinger;
@@ -832,6 +824,7 @@
     FenceTimeline mReleaseTimeline;
 
     // main thread
+    sp<NativeHandle> mSidebandStream;
     // Active buffer fields
     sp<GraphicBuffer> mActiveBuffer;
     sp<Fence> mActiveBufferFence;
@@ -920,11 +913,11 @@
 
 } // namespace android
 
-#define RETURN_IF_NO_HWC_LAYER(displayId, ...)                                         \
+#define RETURN_IF_NO_HWC_LAYER(displayDevice, ...)                                     \
     do {                                                                               \
-        if (!hasHwcLayer(displayId)) {                                                 \
+        if (!hasHwcLayer(displayDevice)) {                                             \
             ALOGE("[%s] %s failed: no HWC layer found for display %s", mName.string(), \
-                  __FUNCTION__, to_string(displayId).c_str());                         \
+                  __FUNCTION__, displayDevice->getDebugName().c_str());                \
             return __VA_ARGS__;                                                        \
         }                                                                              \
     } while (false)
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
index e39babe..9f63440 100644
--- a/services/surfaceflinger/LayerBE.cpp
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -21,45 +21,14 @@
 
 #include "Layer.h"
 
-#include <android-base/stringprintf.h>
-#include <renderengine/RenderEngine.h>
-
-#include <string>
-
-namespace {
-
-const char* getCompositionName(HWC2::Composition compositionType) {
-    switch (compositionType) {
-        case HWC2::Composition::Invalid:
-            return "Invalid";
-        case HWC2::Composition::Client:
-            return "Client";
-        case HWC2::Composition::Device:
-            return "Device";
-        case HWC2::Composition::SolidColor:
-            return "Solid Color";
-        case HWC2::Composition::Cursor:
-            return "Cursor";
-        case HWC2::Composition::Sideband:
-            return "Sideband";
-    }
-    return "Invalid";
-}
-
-}  // namespace anonymous
-
 namespace android {
 
-LayerBE::LayerBE(Layer* layer, std::string layerName)
-      : mLayer(layer),
-        mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
+LayerBE::LayerBE(Layer* layer, std::string layerName) : mLayer(layer) {
     compositionInfo.layer = std::make_shared<LayerBE>(*this);
     compositionInfo.layerName = layerName;
 }
 
-LayerBE::LayerBE(const LayerBE& layer)
-      : mLayer(layer.mLayer),
-        mMesh(renderengine::Mesh::TRIANGLE_FAN, 4, 2, 2) {
+LayerBE::LayerBE(const LayerBE& layer) : mLayer(layer.mLayer) {
     compositionInfo.layer = layer.compositionInfo.layer;
     compositionInfo.layerName = layer.mLayer->getName().string();
 }
@@ -68,101 +37,4 @@
     mLayer->onLayerDisplayed(releaseFence);
 }
 
-void LayerBE::clear(renderengine::RenderEngine& engine) {
-    engine.setupFillWithColor(0, 0, 0, 0);
-    engine.drawMesh(mMesh);
-}
-
-void CompositionInfo::dump(const char* tag) const
-{
-    std::string logString;
-    dump(logString, tag);
-    ALOGV("%s", logString.c_str());
-}
-
-void CompositionInfo::dumpHwc(std::string& result, const char* tag) const {
-    if (tag == nullptr) {
-        result += base::StringPrintf("HWC parameters\n");
-    } else {
-        result += base::StringPrintf("[%s]HWC parameters\n", tag);
-    }
-
-    result += base::StringPrintf("\thwcLayer=%p\n", static_cast<HWC2::Layer*>(&*hwc.hwcLayer));
-    result += base::StringPrintf("\tfence=%p\n", hwc.fence.get());
-    result += base::StringPrintf("\tblendMode=%d\n", hwc.blendMode);
-    result += base::StringPrintf("\ttransform=%d\n", hwc.transform);
-    result += base::StringPrintf("\tz=%d\n", hwc.z);
-    result += base::StringPrintf("\ttype=%d\n", hwc.type);
-    result += base::StringPrintf("\tappId=%d\n", hwc.appId);
-    result += base::StringPrintf("\tdisplayFrame=%4d %4d %4d %4d\n", hwc.displayFrame.left,
-                                 hwc.displayFrame.top, hwc.displayFrame.right,
-                                 hwc.displayFrame.bottom);
-    result += base::StringPrintf("\talpha=%.3f", hwc.alpha);
-    result += base::StringPrintf("\tsourceCrop=%6.1f %6.1f %6.1f %6.1f\n", hwc.sourceCrop.left,
-                                 hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
-
-    hwc.visibleRegion.dump(result, "visibleRegion");
-    hwc.surfaceDamage.dump(result, "surfaceDamage");
-
-    result += base::StringPrintf("\tcolor transform matrix:\n"
-                                 "\t\t[%f, %f, %f, %f,\n"
-                                 "\t\t %f, %f, %f, %f,\n"
-                                 "\t\t %f, %f, %f, %f,\n"
-                                 "\t\t %f, %f, %f, %f]\n",
-                                 hwc.colorTransform[0][0], hwc.colorTransform[1][0],
-                                 hwc.colorTransform[2][0], hwc.colorTransform[3][0],
-                                 hwc.colorTransform[0][1], hwc.colorTransform[1][1],
-                                 hwc.colorTransform[2][1], hwc.colorTransform[3][1],
-                                 hwc.colorTransform[0][2], hwc.colorTransform[1][2],
-                                 hwc.colorTransform[2][2], hwc.colorTransform[3][2],
-                                 hwc.colorTransform[0][3], hwc.colorTransform[1][3],
-                                 hwc.colorTransform[2][3], hwc.colorTransform[3][3]);
-}
-
-void CompositionInfo::dumpRe(std::string& result, const char* tag) const {
-    if (tag == nullptr) {
-        result += base::StringPrintf("RenderEngine parameters:\n");
-    } else {
-        result += base::StringPrintf("[%s]RenderEngine parameters:\n", tag);
-    }
-
-    result += base::StringPrintf("\tblackoutLayer=%d\n", re.blackoutLayer);
-    result += base::StringPrintf("\tclearArea=%d\n", re.clearArea);
-    result += base::StringPrintf("\tpreMultipliedAlpha=%d\n", re.preMultipliedAlpha);
-    result += base::StringPrintf("\topaque=%d\n", re.opaque);
-    result += base::StringPrintf("\tdisableTexture=%d\n", re.disableTexture);
-    result += base::StringPrintf("\tuseIdentityTransform=%d\n", re.useIdentityTransform);
-}
-
-void CompositionInfo::dump(std::string& result, const char* tag) const
-{
-    if (tag == nullptr) {
-        result += base::StringPrintf("CompositionInfo\n");
-    } else {
-        result += base::StringPrintf("[%s]CompositionInfo\n", tag);
-    }
-    result += base::StringPrintf("\tLayerName: %s\n", layerName.c_str());
-    result += base::StringPrintf("\tCompositionType: %s\n",
-                                 getCompositionName(compositionType));
-    result += base::StringPrintf("\tmBuffer = %p\n", mBuffer.get());
-    result += base::StringPrintf("\tmBufferSlot=%d\n", mBufferSlot);
-    result += base::StringPrintf("\tdisplayFrame=%4d %4d %4d %4d\n", hwc.displayFrame.left,
-                                 hwc.displayFrame.top, hwc.displayFrame.right,
-                                 hwc.displayFrame.bottom);
-    result += base::StringPrintf("\talpha=%f\n", hwc.alpha);
-    result += base::StringPrintf("\tsourceCrop=%6.1f %6.1f %6.1f %6.1f\n", hwc.sourceCrop.left,
-                                 hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
-
-    switch (compositionType) {
-        case HWC2::Composition::Device:
-            dumpHwc(result, tag);
-            break;
-        case HWC2::Composition::Client:
-            dumpRe(result, tag);
-            break;
-        default:
-            break;
-    }
-}
-
 }; // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 6270efa..51f7857 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -17,18 +17,12 @@
 #pragma once
 
 #include <stdint.h>
-#include <sys/types.h>
+#include <string.h>
 
-#include <compositionengine/impl/HwcBufferCache.h>
-
-#include <renderengine/Mesh.h>
-#include <renderengine/RenderEngine.h>
-#include <renderengine/Texture.h>
-#include <ui/Region.h>
+#include <ui/Fence.h>
+#include <utils/StrongPointer.h>
 
 #include "DisplayHardware/DisplayIdentification.h"
-#include "DisplayHardware/HWComposer.h"
-#include "SurfaceFlinger.h"
 
 namespace android {
 
@@ -36,48 +30,10 @@
 
 struct CompositionInfo {
     std::string layerName;
-    HWC2::Composition compositionType;
-    bool firstClear = false;
-    sp<GraphicBuffer> mBuffer = nullptr;
-    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
     std::shared_ptr<LayerBE> layer;
     struct {
-        std::shared_ptr<HWC2::Layer> hwcLayer;
         DisplayId displayId;
-        sp<Fence> fence;
-        HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
-        Rect displayFrame;
-        float alpha;
-        FloatRect sourceCrop;
-        HWC2::Transform transform = HWC2::Transform::None;
-        int z;
-        int type;
-        int appId;
-        Region visibleRegion;
-        Region surfaceDamage;
-        sp<NativeHandle> sidebandStream;
-        ui::Dataspace dataspace;
-        hwc_color_t color;
-        bool clearClientTarget = false;
-        bool supportedPerFrameMetadata = false;
-        HdrMetadata hdrMetadata;
-        mat4 colorTransform;
     } hwc;
-    struct {
-        bool blackoutLayer = false;
-        bool clearArea = false;
-        bool preMultipliedAlpha = false;
-        bool opaque = false;
-        bool disableTexture = false;
-        half4 color;
-        bool useIdentityTransform = false;
-        bool Y410BT2020 = false;
-    } re;
-
-    void dump(const char* tag) const;
-    void dump(std::string& result, const char* tag = nullptr) const;
-    void dumpHwc(std::string& result, const char* tag = nullptr) const;
-    void dumpRe(std::string& result, const char* tag = nullptr) const;
 };
 
 class LayerBE {
@@ -96,41 +52,10 @@
     explicit LayerBE(const LayerBE& layer);
 
     void onLayerDisplayed(const sp<Fence>& releaseFence);
-    void clear(renderengine::RenderEngine& renderEngine);
-    renderengine::Mesh& getMesh() { return mMesh; }
 
     Layer*const mLayer;
+
 private:
-    // The mesh used to draw the layer in GLES composition mode
-    renderengine::Mesh mMesh;
-
-    // HWC items, accessed from the main thread
-    struct HWCInfo {
-        HWCInfo()
-              : hwc(nullptr),
-                layer(nullptr),
-                forceClientComposition(false),
-                compositionType(HWC2::Composition::Invalid),
-                clearClientTarget(false),
-                transform(HWC2::Transform::None) {}
-
-        HWComposer* hwc;
-        std::shared_ptr<HWC2::Layer> layer;
-        bool forceClientComposition;
-        HWC2::Composition compositionType;
-        bool clearClientTarget;
-        Rect displayFrame;
-        FloatRect sourceCrop;
-        compositionengine::impl::HwcBufferCache bufferCache;
-        HWC2::Transform transform;
-    };
-
-    // A layer can be attached to multiple displays when operating in mirror mode
-    // (a.k.a: when several displays are attached with equal layerStack). In this
-    // case we need to keep track. In non-mirror mode, a layer will have only one
-    // HWCInfo.
-    std::unordered_map<DisplayId, HWCInfo> mHwcLayers;
-
     CompositionInfo compositionInfo;
 };
 
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 9bad6de..edc6442 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -7,6 +7,8 @@
 
 namespace android {
 
+class DisplayDevice;
+
 // RenderArea describes a rectangular area that layers can be rendered to.
 //
 // There is a logical render area and a physical render area.  When a layer is
@@ -76,6 +78,8 @@
     // covered by any rendered layer should be filled with this color.
     CaptureFill getCaptureFill() const { return mCaptureFill; };
 
+    virtual const sp<const DisplayDevice> getDisplayDevice() const = 0;
+
 private:
     const uint32_t mReqWidth;
     const uint32_t mReqHeight;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c98220d..0ffcae4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -43,7 +43,9 @@
 #include <compositionengine/Layer.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/RenderSurface.h>
+#include <compositionengine/impl/LayerCompositionState.h>
 #include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 #include <dvr/vr_flinger.h>
 #include <gui/BufferQueue.h>
 #include <gui/GuiConfig.h>
@@ -1811,26 +1813,9 @@
                 mHadClientComposition || getHwComposer().hasClientComposition(displayId);
     }
 
-    // Setup RenderEngine sync fences if native sync is supported.
-    if (getRenderEngine().useNativeFenceSync()) {
-        if (mHadClientComposition) {
-            base::unique_fd flushFence(getRenderEngine().flush());
-            ALOGE_IF(flushFence < 0, "Failed to flush RenderEngine!");
-            getBE().flushFence = new Fence(std::move(flushFence));
-        } else {
-            // Cleanup for hygiene.
-            getBE().flushFence = Fence::NO_FENCE;
-        }
-    }
-
     mVsyncModulator.onRefreshed(mHadClientComposition);
 
     getBE().mEndOfFrameCompositionInfo = std::move(getBE().mCompositionInfo);
-    for (const auto& [token, display] : mDisplays) {
-        for (auto& compositionInfo : getBE().mEndOfFrameCompositionInfo[token]) {
-            compositionInfo.hwc.hwcLayer = nullptr;
-        }
-    }
 
     mLayersWithQueuedFrames.clear();
 }
@@ -1871,16 +1856,16 @@
             for (size_t i = 0; i < currentLayers.size(); i++) {
                 const auto& layer = currentLayers[i];
 
-                if (!layer->hasHwcLayer(*displayId)) {
-                    if (!layer->createHwcLayer(&getHwComposer(), *displayId)) {
-                        layer->forceClientComposition(*displayId);
+                if (!layer->hasHwcLayer(displayDevice)) {
+                    if (!layer->createHwcLayer(&getHwComposer(), displayDevice)) {
+                        layer->forceClientComposition(displayDevice);
                         continue;
                     }
                 }
 
                 layer->setGeometry(displayDevice, i);
                 if (mDebugDisableHWC || mDebugRegion) {
-                    layer->forceClientComposition(*displayId);
+                    layer->forceClientComposition(displayDevice);
                 }
             }
         }
@@ -1900,34 +1885,35 @@
         }
         for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             if (layer->isHdrY410()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
                        !profile->hasHDR10Support()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
                        !profile->hasHLGSupport()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             }
 
             // TODO(b/111562338) remove when composer 2.3 is shipped.
             if (layer->hasColorTransform()) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             }
 
             if (layer->getRoundedCornerState().radius > 0.0f) {
-                layer->forceClientComposition(*displayId);
+                layer->forceClientComposition(displayDevice);
             }
 
-            if (layer->getForceClientComposition(*displayId)) {
+            if (layer->getForceClientComposition(displayDevice)) {
                 ALOGV("[%s] Requesting Client composition", layer->getName().string());
-                layer->setCompositionType(*displayId, HWC2::Composition::Client);
+                layer->setCompositionType(displayDevice,
+                                          Hwc2::IComposerClient::Composition::CLIENT);
                 continue;
             }
 
             const auto& displayState = display->getState();
-            layer->setPerFrameData(*displayId, displayState.transform, displayState.viewport,
+            layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
                                    displayDevice->getSupportedPerFrameMetadata());
         }
 
@@ -1942,20 +1928,15 @@
 
     mDrawingState.colorMatrixChanged = false;
 
-    for (const auto& [token, display] : mDisplays) {
-        for (auto& layer : display->getVisibleLayersSortedByZ()) {
+    for (const auto& [token, displayDevice] : mDisplays) {
+        auto display = displayDevice->getCompositionDisplay();
+        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
             const auto displayId = display->getId();
-            layer->getBE().compositionInfo.compositionType = layer->getCompositionType(displayId);
-
-            if (displayId) {
-                if (!layer->setHwcLayer(*displayId)) {
-                    ALOGV("Need to create HWCLayer for %s", layer->getName().string());
-                }
-                layer->getBE().compositionInfo.hwc.displayId = *displayId;
-            }
-
+            auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
+            layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
+                    layer->getCompositionType(displayDevice));
+            layer->getBE().compositionInfo.hwc.displayId = *displayId;
             getBE().mCompositionInfo[token].push_back(layer->getBE().compositionInfo);
-            layer->getBE().compositionInfo.hwc.hwcLayer = nullptr;
         }
     }
 }
@@ -2003,7 +1984,7 @@
     if (CC_UNLIKELY(mLayerStats.isEnabled())) {
         for (const auto& [token, display] : mDisplays) {
             if (display->isPrimary()) {
-                mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(*display));
+                mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(display));
                 return;
             }
         }
@@ -2400,13 +2381,13 @@
                         } else {
                             // Clear out the HWC layer if this layer was
                             // previously visible, but no longer is
-                            hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
+                            hwcLayerDestroyed = displayId && layer->destroyHwcLayer(displayDevice);
                         }
                     } else {
                         // WM changes display->layerStack upon sleep/awake.
                         // Here we make sure we delete the HWC layers even if
                         // WM changed their layer stack.
-                        hwcLayerDestroyed = displayId && layer->destroyHwcLayer(*displayId);
+                        hwcLayerDestroyed = displayId && layer->destroyHwcLayer(displayDevice);
                     }
 
                     // If a layer is not going to get a release fence because
@@ -2576,8 +2557,7 @@
         return;
     }
 
-    status_t result = display->getRenderSurface()->prepareFrame(
-            getBE().mCompositionInfo[displayDevice->getDisplayToken()]);
+    status_t result = display->getRenderSurface()->prepareFrame();
     ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
              displayDevice->getDebugName().c_str(), result, strerror(-result));
 }
@@ -2635,9 +2615,10 @@
             // The layer buffer from the previous frame (if any) is released
             // by HWC only when the release fence from this frame (if any) is
             // signaled.  Always get the release fence from HWC first.
-            if (displayId && layer->hasHwcLayer(*displayId)) {
-                releaseFence = getHwComposer().getLayerReleaseFence(*displayId,
-                                                                    layer->getHwcLayer(*displayId));
+            if (displayId && layer->hasHwcLayer(displayDevice)) {
+                releaseFence =
+                        getHwComposer().getLayerReleaseFence(*displayId,
+                                                             layer->getHwcLayer(displayDevice));
             }
 
             // If the layer was client composited in the previous frame, we
@@ -2645,7 +2626,8 @@
             // Since we do not track that, always merge with the current
             // client target acquire fence when it is available, even though
             // this is suboptimal.
-            if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
+            if (layer->getCompositionType(displayDevice) ==
+                Hwc2::IComposerClient::Composition::CLIENT) {
                 releaseFence =
                         Fence::merge("LayerRelease", releaseFence,
                                      display->getRenderSurface()->getClientTargetAcquireFence());
@@ -3098,6 +3080,7 @@
         });
     }
 
+    commitInputWindowCommands();
     commitTransaction();
 }
 
@@ -3128,6 +3111,11 @@
     mInputFlinger->setInputWindows(inputHandles);
 }
 
+void SurfaceFlinger::commitInputWindowCommands() {
+    mInputWindowCommands.merge(mPendingInputWindowCommands);
+    mPendingInputWindowCommands.clear();
+}
+
 void SurfaceFlinger::executeInputWindowCommands() {
     for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
         if (transferTouchFocusCommand.fromToken != nullptr &&
@@ -3156,16 +3144,8 @@
 
 void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
     if (layer->hasReadyFrame()) {
-        nsecs_t expectedPresentTime;
-        if (mUseScheduler) {
-            expectedPresentTime = mScheduler->expectedPresentTime();
-        } else {
-            expectedPresentTime = mPrimaryDispSync->expectedPresentTime();
-        }
-        if (layer->shouldPresentNow(expectedPresentTime)) {
-            bool ignored = false;
-            layer->latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
-        }
+        bool ignored = false;
+        layer->latchBuffer(ignored, systemTime());
     }
     layer->releasePendingBuffer(systemTime());
 }
@@ -3415,7 +3395,7 @@
         Mutex::Autolock lock(mStateLock);
 
         for (auto& layer : mLayersWithQueuedFrames) {
-            if (layer->latchBuffer(visibleRegions, latchTime, getBE().flushFence)) {
+            if (layer->latchBuffer(visibleRegions, latchTime)) {
                 mLayersPendingRefresh.push_back(layer);
             }
             layer->useSurfaceDamage();
@@ -3425,11 +3405,6 @@
         }
     }
 
-    // Clear the renderengine fence here...
-    // downstream code assumes that a cleared fence == NO_FENCE, so reassign to
-    // clear instead of sp::clear.
-    getBE().flushFence = Fence::NO_FENCE;
-
     mVisibleRegionsDirty |= visibleRegions;
 
     // If we will need to wake up at some time in the future to deal with a
@@ -3556,16 +3531,16 @@
         const Region viewportRegion(displayState.viewport);
         const Region clip(viewportRegion.intersect(layer->visibleRegion));
         ALOGV("Layer: %s", layer->getName().string());
-        ALOGV("  Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
+        ALOGV("  Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
         if (!clip.isEmpty()) {
-            switch (layer->getCompositionType(displayId)) {
-                case HWC2::Composition::Cursor:
-                case HWC2::Composition::Device:
-                case HWC2::Composition::Sideband:
-                case HWC2::Composition::SolidColor: {
+            switch (layer->getCompositionType(displayDevice)) {
+                case Hwc2::IComposerClient::Composition::CURSOR:
+                case Hwc2::IComposerClient::Composition::DEVICE:
+                case Hwc2::IComposerClient::Composition::SIDEBAND:
+                case Hwc2::IComposerClient::Composition::SOLID_COLOR: {
                     LOG_ALWAYS_FATAL_IF(!displayId);
                     const Layer::State& state(layer->getDrawingState());
-                    if (layer->getClearClientTarget(*displayId) && !firstLayer &&
+                    if (layer->getClearClientTarget(displayDevice) && !firstLayer &&
                         layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
                         layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
                         // never clear the very first layer since we're
@@ -3585,7 +3560,7 @@
                     }
                     break;
                 }
-                case HWC2::Composition::Client: {
+                case Hwc2::IComposerClient::Composition::CLIENT: {
                     renderengine::LayerSettings layerSettings;
                     bool prepared =
                             layer->prepareClientLayer(renderArea, clip, clearRegion, layerSettings);
@@ -3702,11 +3677,12 @@
         auto& [applyToken, transactionQueue] = *it;
 
         while (!transactionQueue.empty()) {
-            const auto& [states, displays, flags, desiredPresentTime] = transactionQueue.front();
+            const auto& [states, displays, flags, desiredPresentTime, privileged] =
+                    transactionQueue.front();
             if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
                 break;
             }
-            applyTransactionState(states, displays, flags, mInputWindowCommands);
+            applyTransactionState(states, displays, flags, mPendingInputWindowCommands, privileged);
             transactionQueue.pop();
         }
 
@@ -3770,6 +3746,9 @@
                                          const InputWindowCommands& inputWindowCommands,
                                          int64_t desiredPresentTime) {
     ATRACE_CALL();
+
+    bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
+
     Mutex::Autolock _l(mStateLock);
 
     if (containsAnyInvalidClientState(states)) {
@@ -3779,17 +3758,19 @@
     // If its TransactionQueue already has a pending TransactionState or if it is pending
     if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() ||
         !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
-        mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime);
+        mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
+                privileged);
         setTransactionFlags(eTransactionNeeded);
         return;
     }
 
-    applyTransactionState(states, displays, flags, inputWindowCommands);
+    applyTransactionState(states, displays, flags, inputWindowCommands, privileged);
 }
 
 void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
                                            const Vector<DisplayState>& displays, uint32_t flags,
-                                           const InputWindowCommands& inputWindowCommands) {
+                                           const InputWindowCommands& inputWindowCommands,
+                                           bool privileged) {
     uint32_t transactionFlags = 0;
 
     if (flags & eAnimation) {
@@ -3814,7 +3795,7 @@
 
     uint32_t clientStateFlags = 0;
     for (const ComposerState& state : states) {
-        clientStateFlags |= setClientStateLocked(state);
+        clientStateFlags |= setClientStateLocked(state, privileged);
     }
     // If the state doesn't require a traversal and there are callbacks, send them now
     if (!(clientStateFlags & eTraversalNeeded)) {
@@ -3912,7 +3893,7 @@
     return flags;
 }
 
-bool callingThreadHasUnscopedSurfaceFlingerAccess() {
+bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess() {
     IPCThreadState* ipc = IPCThreadState::self();
     const int pid = ipc->getCallingPid();
     const int uid = ipc->getCallingUid();
@@ -3923,7 +3904,8 @@
     return true;
 }
 
-uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState) {
+uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState,
+        bool privileged) {
     const layer_state_t& s = composerState.state;
     sp<Client> client(static_cast<Client*>(composerState.client.get()));
 
@@ -4024,7 +4006,7 @@
         // of cropped areas, we need to prevent non-root clients without permission ACCESS_SURFACE_FLINGER
         // (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving
         // transformations.
-        if (layer->setMatrix(s.matrix, callingThreadHasUnscopedSurfaceFlingerAccess()))
+        if (layer->setMatrix(s.matrix, privileged))
             flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eTransparentRegionChanged) {
@@ -4174,7 +4156,7 @@
         flags |= eTraversalNeeded;
     }
 
-    mInputWindowCommands.merge(inputWindowCommands);
+    mPendingInputWindowCommands.merge(inputWindowCommands);
     return flags;
 }
 
@@ -4390,7 +4372,7 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-    setTransactionState(state, displays, 0, nullptr, mInputWindowCommands, -1);
+    setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1);
 
     setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
 
@@ -4574,7 +4556,6 @@
                  })},
                 {"--dump-layer-stats"s, dumper([this](std::string& s) { mLayerStats.dump(s); })},
                 {"--enable-layer-stats"s, dumper([this](std::string&) { mLayerStats.enable(); })},
-                {"--frame-composition"s, dumper(&SurfaceFlinger::dumpFrameCompositionInfo)},
                 {"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
                 {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
                 {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
@@ -4828,23 +4809,6 @@
     result.append("\n");
 }
 
-void SurfaceFlinger::dumpFrameCompositionInfo(std::string& result) const {
-    for (const auto& [token, display] : mDisplays) {
-        const auto it = getBE().mEndOfFrameCompositionInfo.find(token);
-        if (it == getBE().mEndOfFrameCompositionInfo.end()) {
-            continue;
-        }
-
-        const auto& compositionInfoList = it->second;
-        StringAppendF(&result, "%s\n", display->getDebugName().c_str());
-        StringAppendF(&result, "numComponents: %zu\n", compositionInfoList.size());
-        for (const auto& compositionInfo : compositionInfoList) {
-            compositionInfo.dump(result, nullptr);
-            result.append("\n");
-        }
-    }
-}
-
 LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet) const {
     LayersProto layersProto;
     const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
@@ -4857,26 +4821,27 @@
     return layersProto;
 }
 
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& displayDevice) const {
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
+        const sp<DisplayDevice>& displayDevice) const {
     LayersProto layersProto;
 
     SizeProto* resolution = layersProto.mutable_resolution();
-    resolution->set_w(displayDevice.getWidth());
-    resolution->set_h(displayDevice.getHeight());
+    resolution->set_w(displayDevice->getWidth());
+    resolution->set_h(displayDevice->getHeight());
 
-    auto display = displayDevice.getCompositionDisplay();
+    auto display = displayDevice->getCompositionDisplay();
     const auto& displayState = display->getState();
 
     layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
     layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
     layersProto.set_global_transform(displayState.orientation);
 
-    const auto displayId = displayDevice.getId();
+    const auto displayId = displayDevice->getId();
     LOG_ALWAYS_FATAL_IF(!displayId);
     mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(*displayId)) {
+        if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
             LayerProto* layerProto = layersProto.add_layers();
-            layer->writeToProto(layerProto, *displayId);
+            layer->writeToProto(layerProto, displayDevice);
         }
     });
 
@@ -4945,10 +4910,6 @@
         result.append("\n");
     }
 
-    result.append("\nFrame-Composition information:\n");
-    dumpFrameCompositionInfo(result);
-    result.append("\n");
-
     /*
      * Dump Display state
      */
@@ -5012,7 +4973,9 @@
 
         StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str());
         Layer::miniDumpHeader(result);
-        mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, *displayId); });
+        const sp<DisplayDevice> displayDevice = display;
+        mCurrentState.traverseInZOrder(
+                [&](Layer* layer) { layer->miniDump(result, displayDevice); });
         result.append("\n");
     }
 
@@ -5564,6 +5527,7 @@
         }
         bool isSecure() const override { return false; }
         bool needsFiltering() const override { return mNeedsFiltering; }
+        const sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
         Rect getSourceCrop() const override {
             if (mCrop.isEmpty()) {
                 return getBounds();
@@ -5583,7 +5547,7 @@
                 newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform());
                 oldParent->setChildrenDrawingParent(newParent);
             }
-            ~ReparentForDrawing() { newParent->setChildrenDrawingParent(oldParent); }
+            ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
         };
 
         void render(std::function<void()> drawLayers) override {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a0f83a2..45cec20 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -169,9 +169,6 @@
     nsecs_t mTotalTime;
     std::atomic<nsecs_t> mLastSwapTime;
 
-    // Synchronization fence from a GL composition.
-    sp<Fence> flushFence = Fence::NO_FENCE;
-
     // Double- vs. triple-buffering stats
     struct BufferingStats {
         BufferingStats()
@@ -408,6 +405,7 @@
      */
     status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override;
     status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); }
+    bool callingThreadHasUnscopedSurfaceFlingerAccess() EXCLUDES(mStateLock);
 
     /* ------------------------------------------------------------------------
      * ISurfaceComposer interface
@@ -534,10 +532,11 @@
     void handleMessageRefresh();
 
     void handleTransaction(uint32_t transactionFlags);
-    void handleTransactionLocked(uint32_t transactionFlags);
+    void handleTransactionLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
 
     void updateInputFlinger();
     void updateInputWindowInfo();
+    void commitInputWindowCommands() REQUIRES(mStateLock);
     void executeInputWindowCommands();
     void updateCursorAsync();
 
@@ -552,7 +551,8 @@
      */
     void applyTransactionState(const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
-                               const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock);
+                               const InputWindowCommands& inputWindowCommands,
+                               bool privileged) REQUIRES(mStateLock);
     bool flushTransactionQueues();
     uint32_t getTransactionFlags(uint32_t flags);
     uint32_t peekTransactionFlags();
@@ -564,9 +564,10 @@
     bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                        const Vector<ComposerState>& states);
-    uint32_t setClientStateLocked(const ComposerState& composerState);
+    uint32_t setClientStateLocked(const ComposerState& composerState, bool privileged);
     uint32_t setDisplayStateLocked(const DisplayState& s);
-    uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands);
+    uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
+            REQUIRES(mStateLock);
 
     /* ------------------------------------------------------------------------
      * Layer management
@@ -893,9 +894,8 @@
     void dumpBufferingStats(std::string& result) const;
     void dumpDisplayIdentificationData(std::string& result) const;
     void dumpWideColorInfo(std::string& result) const;
-    void dumpFrameCompositionInfo(std::string& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
-    LayersProto dumpVisibleLayersProtoInfo(const DisplayDevice& display) const;
+    LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -1054,16 +1054,19 @@
     struct TransactionState {
         TransactionState(const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         int64_t desiredPresentTime)
+                         int64_t desiredPresentTime,
+                         bool privileged)
               : states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
-                time(desiredPresentTime) {}
+                time(desiredPresentTime),
+                privileged(privileged) {}
 
         Vector<ComposerState> states;
         Vector<DisplayState> displays;
         uint32_t flags;
         int64_t time;
+        bool privileged;
     };
     std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues;
 
@@ -1144,6 +1147,8 @@
     /* ------------------------------------------------------------------------ */
     sp<IInputFlinger> mInputFlinger;
 
+    InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
+    // Should only be accessed by the main thread.
     InputWindowCommands mInputWindowCommands;
 
     ui::DisplayPrimaries mInternalDisplayPrimaries;
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 68cf61e..a2c0611 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -31,7 +31,6 @@
         "libutils",
     ],
     static_libs: [
-        "libcompositionengine",
         "libgmock",
         "librenderengine",
         "libtrace_proto",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 3fb8708..55a348e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -17,6 +17,7 @@
 #undef LOG_TAG
 #define LOG_TAG "CompositionTest"
 
+#include <compositionengine/Display.h>
 #include <compositionengine/mock/DisplaySurface.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
@@ -481,7 +482,7 @@
 
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
         bool ignoredRecomputeVisibleRegions;
-        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, Fence::NO_FENCE);
+        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
         Mock::VerifyAndClear(test->mRenderEngine);
     }
 
@@ -753,12 +754,16 @@
     }
 
     static void injectLayer(CompositionTest* test, sp<Layer> layer) {
+        std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
+        outputLayers.emplace_back(
+                test->mDisplay->getCompositionDisplay()
+                        ->getOrCreateOutputLayer(layer->getCompositionLayer(), layer));
+        test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
+
         EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
                 .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
 
-        const auto displayId = test->mDisplay->getId();
-        ASSERT_TRUE(displayId);
-        layer->createHwcLayer(&test->mFlinger.getHwComposer(), *displayId);
+        layer->createHwcLayer(&test->mFlinger.getHwComposer(), test->mDisplay);
 
         Mock::VerifyAndClear(test->mComposer);
 
@@ -771,10 +776,12 @@
     static void cleanupInjectedLayers(CompositionTest* test) {
         EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
                 .WillOnce(Return(Error::NONE));
-        const auto displayId = test->mDisplay->getId();
-        ASSERT_TRUE(displayId);
+
+        test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(
+                std::vector<std::unique_ptr<compositionengine::OutputLayer>>());
+
         for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
-            layer->destroyHwcLayer(*displayId);
+            layer->destroyHwcLayer(test->mDisplay);
         }
         test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
     }
@@ -963,8 +970,8 @@
 };
 
 struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
-    static void setupLayerState(CompositionTest*, sp<Layer> layer) {
-        layer->forceClientComposition(DEFAULT_DISPLAY_ID);
+    static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
+        layer->forceClientComposition(test->mDisplay);
     }
 
     template <typename Case>
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index e639b4d..959126e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -16,7 +16,12 @@
 
 #pragma once
 
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
 
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
@@ -203,9 +208,18 @@
 
     void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
         layer->mDrawingState.sidebandStream = sidebandStream;
-        layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
+        layer->mSidebandStream = sidebandStream;
+        layer->getCompositionLayer()->editState().frontEnd.sidebandStream = sidebandStream;
     }
 
+    void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
+        auto outputLayer = layer->findOutputLayerForDisplay(mFlinger->getDefaultDisplayDevice());
+        LOG_ALWAYS_FATAL_IF(!outputLayer);
+        auto& state = outputLayer->editState();
+        LOG_ALWAYS_FATAL_IF(!outputLayer->getState().hwc);
+        (*state.hwc).hwcCompositionType = static_cast<Hwc2::IComposerClient::Composition>(type);
+    };
+
     void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
         layer->mPotentialCursor = potentialCursor;
     }
@@ -234,6 +248,7 @@
     }
 
     auto handleTransactionLocked(uint32_t transactionFlags) {
+        Mutex::Autolock _l(mFlinger->mStateLock);
         return mFlinger->handleTransactionLocked(transactionFlags);
     }
 
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index f3e54a0..b49d894 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -91,11 +91,10 @@
 
   // Using placement new here to reuse shared memory instead of new allocation
   // and also initialize the value to zero.
-  buffer_state_ =
-      new (&metadata_header_->buffer_state) std::atomic<uint32_t>(0);
-  fence_state_ = new (&metadata_header_->fence_state) std::atomic<uint32_t>(0);
+  buffer_state_ = new (&metadata_header_->bufferState) std::atomic<uint32_t>(0);
+  fence_state_ = new (&metadata_header_->fenceState) std::atomic<uint32_t>(0);
   active_clients_bit_mask_ =
-      new (&metadata_header_->active_clients_bit_mask) std::atomic<uint32_t>(0);
+      new (&metadata_header_->activeClientsBitMask) std::atomic<uint32_t>(0);
 
   // Producer channel is never created after consumer channel, and one buffer
   // only have one fixed producer for now. Thus, it is correct to assume
@@ -183,7 +182,7 @@
                     buffer_.height(), buffer_.layer_count(), buffer_.format(),
                     buffer_.usage(),
                     buffer_state_->load(std::memory_order_acquire),
-                    signaled_mask, metadata_header_->queue_index);
+                    signaled_mask, metadata_header_->queueIndex);
 }
 
 void ProducerChannel::HandleImpulse(Message& message) {
@@ -547,7 +546,7 @@
           "%s: orphaned buffer detected during the this acquire/release cycle: "
           "id=%d orphaned=0x%" PRIx32 " queue_index=%" PRId64 ".",
           __FUNCTION__, buffer_id(), orphaned_consumer_bit_mask_,
-          metadata_header_->queue_index);
+          metadata_header_->queueIndex);
       orphaned_consumer_bit_mask_ = 0;
     }
   }
@@ -581,7 +580,7 @@
       "consumer_state_mask=%" PRIx32 " queue_index=%" PRId64
       " buffer_state=%" PRIx32 " fence_state=%" PRIx32 ".",
       __FUNCTION__, buffer_id(), consumer_state_mask,
-      metadata_header_->queue_index,
+      metadata_header_->queueIndex,
       buffer_state_->load(std::memory_order_acquire),
       fence_state_->load(std::memory_order_acquire));
 }