Merge "Updating ISurfaceComposer to report errors"
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 4140f40..d9ff4ba 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -489,7 +489,7 @@
 
     Rect r = Rect(cc.rectangle().left(), cc.rectangle().top(), cc.rectangle().right(),
             cc.rectangle().bottom());
-    t.setCrop(mLayers[id], r);
+    t.setCrop_legacy(mLayers[id], r);
 }
 
 void Replayer::setFinalCrop(SurfaceComposerClient::Transaction& t,
@@ -499,7 +499,7 @@
             fcc.rectangle().bottom());
     Rect r = Rect(fcc.rectangle().left(), fcc.rectangle().top(), fcc.rectangle().right(),
             fcc.rectangle().bottom());
-    t.setFinalCrop(mLayers[id], r);
+    t.setFinalCrop_legacy(mLayers[id], r);
 }
 
 void Replayer::setMatrix(SurfaceComposerClient::Transaction& t,
@@ -570,7 +570,7 @@
 
     auto handle = mLayers[dtc.layer_id()]->getHandle();
 
-    t.deferTransactionUntil(mLayers[id], handle, dtc.frame_number());
+    t.deferTransactionUntil_legacy(mLayers[id], handle, dtc.frame_number());
 }
 
 void Replayer::setDisplaySurface(SurfaceComposerClient::Transaction& t,
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index b772f70..8c3ff74 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -21,6 +21,7 @@
 
 /**
  * @file sharedmem.h
+ * @brief Shared memory buffers that can be shared across process.
  */
 
 #ifndef ANDROID_SHARED_MEMORY_H
@@ -45,10 +46,6 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
-/**
- * Structures and functions for a shared memory buffer that can be shared across process.
- */
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -64,6 +61,8 @@
  *
  * Use close() to release the shared memory region.
  *
+ * Available since API level 26.
+ *
  * \param name an optional name.
  * \param size size of the shared memory region
  * \return file descriptor that denotes the shared memory; error code on failure.
@@ -73,6 +72,8 @@
 /**
  * Get the size of the shared memory region.
  *
+ * Available since API level 26.
+ *
  * \param fd file descriptor of the shared memory region
  * \return size in bytes; 0 if fd is not a valid shared memory file descriptor.
  */
@@ -102,6 +103,8 @@
  *
  *     // share fd with another process here and the other process can only map with PROT_READ.
  *
+ * Available since API level 26.
+ *
  * \param fd   file descriptor of the shared memory region.
  * \param prot any bitwise-or'ed combination of PROT_READ, PROT_WRITE, PROT_EXEC denoting
  *             updated access. Note access can only be removed, but not added back.
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
index e42f9a1..13e56e6 100644
--- a/include/android/sharedmem_jni.h
+++ b/include/android/sharedmem_jni.h
@@ -21,6 +21,7 @@
 
 /**
  * @file sharedmem_jni.h
+ * @brief Shared memory buffers that can be shared across process.
  */
 
 #ifndef ANDROID_SHARED_MEMORY_JNI_H
@@ -47,10 +48,6 @@
  *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
  */
 
-/**
- * Structures and functions for a shared memory buffer that can be shared across process.
- */
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -65,6 +62,8 @@
  *
  * Use close() to release the shared memory region.
  *
+ * Available since API level 27.
+ *
  * \param env The JNIEnv* pointer
  * \param sharedMemory The Java android.os.SharedMemory object
  * \return file descriptor that denotes the shared memory; -1 if the shared memory object is
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 01acc2d..931c446 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -37,19 +37,45 @@
     output.writeUint32(mask);
     *reinterpret_cast<layer_state_t::matrix22_t *>(
             output.writeInplace(sizeof(layer_state_t::matrix22_t))) = matrix;
-    output.write(crop);
-    output.write(finalCrop);
-    output.writeStrongBinder(barrierHandle);
+    output.write(crop_legacy);
+    output.write(finalCrop_legacy);
+    output.writeStrongBinder(barrierHandle_legacy);
     output.writeStrongBinder(reparentHandle);
-    output.writeUint64(frameNumber);
+    output.writeUint64(frameNumber_legacy);
     output.writeInt32(overrideScalingMode);
-    output.writeStrongBinder(IInterface::asBinder(barrierGbp));
+    output.writeStrongBinder(IInterface::asBinder(barrierGbp_legacy));
     output.writeStrongBinder(relativeLayerHandle);
     output.writeStrongBinder(parentHandleForChild);
     output.writeFloat(color.r);
     output.writeFloat(color.g);
     output.writeFloat(color.b);
     output.write(transparentRegion);
+    output.writeUint32(transform);
+    output.writeBool(transformToDisplayInverse);
+    output.write(crop);
+    if (buffer) {
+        output.writeBool(true);
+        output.write(*buffer);
+    } else {
+        output.writeBool(false);
+    }
+    if (acquireFence) {
+        output.writeBool(true);
+        output.write(*acquireFence);
+    } else {
+        output.writeBool(false);
+    }
+    output.writeUint32(static_cast<uint32_t>(dataspace));
+    output.write(hdrMetadata);
+    output.write(surfaceDamageRegion);
+    output.writeInt32(api);
+    if (sidebandStream) {
+        output.writeBool(true);
+        output.writeNativeHandle(sidebandStream->handle());
+    } else {
+        output.writeBool(false);
+    }
+
     return NO_ERROR;
 }
 
@@ -72,20 +98,38 @@
     } else {
         return BAD_VALUE;
     }
-    input.read(crop);
-    input.read(finalCrop);
-    barrierHandle = input.readStrongBinder();
+    input.read(crop_legacy);
+    input.read(finalCrop_legacy);
+    barrierHandle_legacy = input.readStrongBinder();
     reparentHandle = input.readStrongBinder();
-    frameNumber = input.readUint64();
+    frameNumber_legacy = input.readUint64();
     overrideScalingMode = input.readInt32();
-    barrierGbp =
-        interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
+    barrierGbp_legacy = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
     relativeLayerHandle = input.readStrongBinder();
     parentHandleForChild = input.readStrongBinder();
     color.r = input.readFloat();
     color.g = input.readFloat();
     color.b = input.readFloat();
     input.read(transparentRegion);
+    transform = input.readUint32();
+    transformToDisplayInverse = input.readBool();
+    input.read(crop);
+    buffer = new GraphicBuffer();
+    if (input.readBool()) {
+        input.read(*buffer);
+    }
+    acquireFence = new Fence();
+    if (input.readBool()) {
+        input.read(*acquireFence);
+    }
+    dataspace = static_cast<ui::Dataspace>(input.readUint32());
+    input.read(hdrMetadata);
+    input.read(surfaceDamageRegion);
+    api = input.readInt32();
+    if (input.readBool()) {
+        sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
+    }
+
     return NO_ERROR;
 }
 
@@ -194,19 +238,19 @@
         what |= eLayerStackChanged;
         layerStack = other.layerStack;
     }
-    if (other.what & eCropChanged) {
-        what |= eCropChanged;
-        crop = other.crop;
+    if (other.what & eCropChanged_legacy) {
+        what |= eCropChanged_legacy;
+        crop_legacy = other.crop_legacy;
     }
-    if (other.what & eDeferTransaction) {
-        what |= eDeferTransaction;
-        barrierHandle = other.barrierHandle;
-        barrierGbp = other.barrierGbp;
-        frameNumber = other.frameNumber;
+    if (other.what & eDeferTransaction_legacy) {
+        what |= eDeferTransaction_legacy;
+        barrierHandle_legacy = other.barrierHandle_legacy;
+        barrierGbp_legacy = other.barrierGbp_legacy;
+        frameNumber_legacy = other.frameNumber_legacy;
     }
-    if (other.what & eFinalCropChanged) {
-        what |= eFinalCropChanged;
-        finalCrop = other.finalCrop;
+    if (other.what & eFinalCropChanged_legacy) {
+        what |= eFinalCropChanged_legacy;
+        finalCrop_legacy = other.finalCrop_legacy;
     }
     if (other.what & eOverrideScalingModeChanged) {
         what |= eOverrideScalingModeChanged;
@@ -234,6 +278,46 @@
     if (other.what & eDestroySurface) {
         what |= eDestroySurface;
     }
+    if (other.what & eTransformChanged) {
+        what |= eTransformChanged;
+        transform = other.transform;
+    }
+    if (other.what & eTransformToDisplayInverseChanged) {
+        what |= eTransformToDisplayInverseChanged;
+        transformToDisplayInverse = other.transformToDisplayInverse;
+    }
+    if (other.what & eCropChanged) {
+        what |= eCropChanged;
+        crop = other.crop;
+    }
+    if (other.what & eBufferChanged) {
+        what |= eBufferChanged;
+        buffer = other.buffer;
+    }
+    if (other.what & eAcquireFenceChanged) {
+        what |= eAcquireFenceChanged;
+        acquireFence = other.acquireFence;
+    }
+    if (other.what & eDataspaceChanged) {
+        what |= eDataspaceChanged;
+        dataspace = other.dataspace;
+    }
+    if (other.what & eHdrMetadataChanged) {
+        what |= eHdrMetadataChanged;
+        hdrMetadata = other.hdrMetadata;
+    }
+    if (other.what & eSurfaceDamageRegionChanged) {
+        what |= eSurfaceDamageRegionChanged;
+        surfaceDamageRegion = other.surfaceDamageRegion;
+    }
+    if (other.what & eApiChanged) {
+        what |= eApiChanged;
+        api = other.api;
+    }
+    if (other.what & eSidebandStreamChanged) {
+        what |= eSidebandStreamChanged;
+        sidebandStream = other.sidebandStream;
+    }
 }
 
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index fc076d2..17cff54 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -344,54 +344,57 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop_legacy(
         const sp<SurfaceControl>& sc, const Rect& crop) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eCropChanged;
-    s->crop = crop;
+    s->what |= layer_state_t::eCropChanged_legacy;
+    s->crop_legacy = crop;
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop) {
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFinalCrop_legacy(
+        const sp<SurfaceControl>& sc, const Rect& crop) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eFinalCropChanged;
-    s->finalCrop = crop;
+    s->what |= layer_state_t::eFinalCropChanged_legacy;
+    s->finalCrop_legacy = crop;
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
-        const sp<SurfaceControl>& sc,
-        const sp<IBinder>& handle, uint64_t frameNumber) {
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+                                                                 const sp<IBinder>& handle,
+                                                                 uint64_t frameNumber) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eDeferTransaction;
-    s->barrierHandle = handle;
-    s->frameNumber = frameNumber;
+    s->what |= layer_state_t::eDeferTransaction_legacy;
+    s->barrierHandle_legacy = handle;
+    s->frameNumber_legacy = frameNumber;
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::deferTransactionUntil(
-        const sp<SurfaceControl>& sc,
-        const sp<Surface>& barrierSurface, uint64_t frameNumber) {
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+                                                                 const sp<Surface>& barrierSurface,
+                                                                 uint64_t frameNumber) {
     layer_state_t* s = getLayerState(sc);
     if (!s) {
         mStatus = BAD_INDEX;
         return *this;
     }
-    s->what |= layer_state_t::eDeferTransaction;
-    s->barrierGbp = barrierSurface->getIGraphicBufferProducer();
-    s->frameNumber = frameNumber;
+    s->what |= layer_state_t::eDeferTransaction_legacy;
+    s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer();
+    s->frameNumber_legacy = frameNumber;
     return *this;
 }
 
@@ -434,6 +437,127 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransform(
+        const sp<SurfaceControl>& sc, uint32_t transform) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eTransformChanged;
+    s->transform = transform;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction&
+SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
+                                                                 bool transformToDisplayInverse) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eTransformToDisplayInverseChanged;
+    s->transformToDisplayInverse = transformToDisplayInverse;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop(
+        const sp<SurfaceControl>& sc, const Rect& crop) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eCropChanged;
+    s->crop = crop;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer(
+        const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eBufferChanged;
+    s->buffer = buffer;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence(
+        const sp<SurfaceControl>& sc, const sp<Fence>& fence) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eAcquireFenceChanged;
+    s->acquireFence = fence;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDataspace(
+        const sp<SurfaceControl>& sc, ui::Dataspace dataspace) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eDataspaceChanged;
+    s->dataspace = dataspace;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMetadata(
+        const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eHdrMetadataChanged;
+    s->hdrMetadata = hdrMetadata;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSurfaceDamageRegion(
+        const sp<SurfaceControl>& sc, const Region& surfaceDamageRegion) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eSurfaceDamageRegionChanged;
+    s->surfaceDamageRegion = surfaceDamageRegion;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApi(
+        const sp<SurfaceControl>& sc, int32_t api) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eApiChanged;
+    s->api = api;
+    return *this;
+}
+
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSidebandStream(
+        const sp<SurfaceControl>& sc, const sp<NativeHandle>& sidebandStream) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eSidebandStreamChanged;
+    s->sidebandStream = sidebandStream;
+    return *this;
+}
+
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
         const sp<SurfaceControl>& sc) {
     layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 8dfc99a..11261c3 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -40,8 +40,9 @@
         eProtectedByDRM = 0x00001000,
         eCursorWindow = 0x00002000,
 
-        eFXSurfaceNormal = 0x00000000,
+        eFXSurfaceBufferQueue = 0x00000000,
         eFXSurfaceColor = 0x00020000,
+        eFXSurfaceBufferState = 0x00040000,
         eFXSurfaceMask = 0x000F0000,
     };
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 788962e..0981798 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -22,10 +22,11 @@
 
 #include <utils/Errors.h>
 
-#include <ui/Region.h>
-#include <ui/Rect.h>
 #include <gui/IGraphicBufferProducer.h>
 #include <math/vec3.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
 
 namespace android {
 
@@ -36,113 +37,146 @@
  * Used to communicate layer information between SurfaceFlinger and its clients.
  */
 struct layer_state_t {
-
-
     enum {
-        eLayerHidden        = 0x01,     // SURFACE_HIDDEN in SurfaceControl.java
-        eLayerOpaque        = 0x02,     // SURFACE_OPAQUE
-        eLayerSecure        = 0x80,     // SECURE
+        eLayerHidden = 0x01, // SURFACE_HIDDEN in SurfaceControl.java
+        eLayerOpaque = 0x02, // SURFACE_OPAQUE
+        eLayerSecure = 0x80, // SECURE
     };
 
     enum {
-        ePositionChanged            = 0x00000001,
-        eLayerChanged               = 0x00000002,
-        eSizeChanged                = 0x00000004,
-        eAlphaChanged               = 0x00000008,
-        eMatrixChanged              = 0x00000010,
-        eTransparentRegionChanged   = 0x00000020,
-        eFlagsChanged               = 0x00000040,
-        eLayerStackChanged          = 0x00000080,
-        eCropChanged                = 0x00000100,
-        eDeferTransaction           = 0x00000200,
-        eFinalCropChanged           = 0x00000400,
+        ePositionChanged = 0x00000001,
+        eLayerChanged = 0x00000002,
+        eSizeChanged = 0x00000004,
+        eAlphaChanged = 0x00000008,
+        eMatrixChanged = 0x00000010,
+        eTransparentRegionChanged = 0x00000020,
+        eFlagsChanged = 0x00000040,
+        eLayerStackChanged = 0x00000080,
+        eCropChanged_legacy = 0x00000100,
+        eDeferTransaction_legacy = 0x00000200,
+        eFinalCropChanged_legacy = 0x00000400,
         eOverrideScalingModeChanged = 0x00000800,
-        eGeometryAppliesWithResize  = 0x00001000,
-        eReparentChildren           = 0x00002000,
-        eDetachChildren             = 0x00004000,
-        eRelativeLayerChanged       = 0x00008000,
-        eReparent                   = 0x00010000,
-        eColorChanged               = 0x00020000,
-        eDestroySurface             = 0x00040000
+        eGeometryAppliesWithResize = 0x00001000,
+        eReparentChildren = 0x00002000,
+        eDetachChildren = 0x00004000,
+        eRelativeLayerChanged = 0x00008000,
+        eReparent = 0x00010000,
+        eColorChanged = 0x00020000,
+        eDestroySurface = 0x00040000,
+        eTransformChanged = 0x00100000,
+        eTransformToDisplayInverseChanged = 0x00200000,
+        eCropChanged = 0x00400000,
+        eBufferChanged = 0x00800000,
+        eAcquireFenceChanged = 0x01000000,
+        eDataspaceChanged = 0x02000000,
+        eHdrMetadataChanged = 0x04000000,
+        eSurfaceDamageRegionChanged = 0x08000000,
+        eApiChanged = 0x10000000,
+        eSidebandStreamChanged = 0x20000000,
     };
 
     layer_state_t()
-        :   what(0),
-            x(0), y(0), z(0), w(0), h(0), layerStack(0),
-            alpha(0), flags(0), mask(0),
-            reserved(0), crop(Rect::INVALID_RECT),
-            finalCrop(Rect::INVALID_RECT), frameNumber(0),
-            overrideScalingMode(-1)
-    {
+          : what(0),
+            x(0),
+            y(0),
+            z(0),
+            w(0),
+            h(0),
+            layerStack(0),
+            alpha(0),
+            flags(0),
+            mask(0),
+            reserved(0),
+            crop_legacy(Rect::INVALID_RECT),
+            finalCrop_legacy(Rect::INVALID_RECT),
+            frameNumber_legacy(0),
+            overrideScalingMode(-1),
+            transform(0),
+            transformToDisplayInverse(false),
+            crop(Rect::INVALID_RECT),
+            dataspace(ui::Dataspace::UNKNOWN),
+            surfaceDamageRegion(),
+            api(-1) {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
+        hdrMetadata.validTypes = 0;
     }
 
     void merge(const layer_state_t& other);
-    status_t    write(Parcel& output) const;
-    status_t    read(const Parcel& input);
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
 
-            struct matrix22_t {
-                float   dsdx{0};
-                float   dtdx{0};
-                float   dtdy{0};
-                float   dsdy{0};
-            };
-            sp<IBinder>     surface;
-            uint32_t        what;
-            float           x;
-            float           y;
-            int32_t         z;
-            uint32_t        w;
-            uint32_t        h;
-            uint32_t        layerStack;
-            float           alpha;
-            uint8_t         flags;
-            uint8_t         mask;
-            uint8_t         reserved;
-            matrix22_t      matrix;
-            Rect            crop;
-            Rect            finalCrop;
-            sp<IBinder>     barrierHandle;
-            sp<IBinder>     reparentHandle;
-            uint64_t        frameNumber;
-            int32_t         overrideScalingMode;
+    struct matrix22_t {
+        float dsdx{0};
+        float dtdx{0};
+        float dtdy{0};
+        float dsdy{0};
+    };
+    sp<IBinder> surface;
+    uint32_t what;
+    float x;
+    float y;
+    int32_t z;
+    uint32_t w;
+    uint32_t h;
+    uint32_t layerStack;
+    float alpha;
+    uint8_t flags;
+    uint8_t mask;
+    uint8_t reserved;
+    matrix22_t matrix;
+    Rect crop_legacy;
+    Rect finalCrop_legacy;
+    sp<IBinder> barrierHandle_legacy;
+    sp<IBinder> reparentHandle;
+    uint64_t frameNumber_legacy;
+    int32_t overrideScalingMode;
 
-            sp<IGraphicBufferProducer> barrierGbp;
+    sp<IGraphicBufferProducer> barrierGbp_legacy;
 
-            sp<IBinder>     relativeLayerHandle;
+    sp<IBinder> relativeLayerHandle;
 
-            sp<IBinder>     parentHandleForChild;
+    sp<IBinder> parentHandleForChild;
 
-            half3           color;
+    half3 color;
 
-            // non POD must be last. see write/read
-            Region          transparentRegion;
+    // non POD must be last. see write/read
+    Region transparentRegion;
+
+    uint32_t transform;
+    bool transformToDisplayInverse;
+    Rect crop;
+    sp<GraphicBuffer> buffer;
+    sp<Fence> acquireFence;
+    ui::Dataspace dataspace;
+    HdrMetadata hdrMetadata;
+    Region surfaceDamageRegion;
+    int32_t api;
+    sp<NativeHandle> sidebandStream;
 };
 
 struct ComposerState {
     sp<ISurfaceComposerClient> client;
     layer_state_t state;
-    status_t    write(Parcel& output) const;
-    status_t    read(const Parcel& input);
+    status_t write(Parcel& output) const;
+    status_t read(const Parcel& input);
 };
 
 struct DisplayState {
-
     enum {
-        eOrientationDefault     = 0,
-        eOrientation90          = 1,
-        eOrientation180         = 2,
-        eOrientation270         = 3,
-        eOrientationUnchanged   = 4,
-        eOrientationSwapMask    = 0x01
+        eOrientationDefault = 0,
+        eOrientation90 = 1,
+        eOrientation180 = 2,
+        eOrientation270 = 3,
+        eOrientationUnchanged = 4,
+        eOrientationSwapMask = 0x01
     };
 
     enum {
-        eSurfaceChanged             = 0x01,
-        eLayerStackChanged          = 0x02,
-        eDisplayProjectionChanged   = 0x04,
-        eDisplaySizeChanged         = 0x08
+        eSurfaceChanged = 0x01,
+        eLayerStackChanged = 0x02,
+        eDisplayProjectionChanged = 0x04,
+        eDisplaySizeChanged = 0x08
     };
 
     DisplayState();
@@ -160,21 +194,18 @@
     status_t read(const Parcel& input);
 };
 
-static inline
-int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
+static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
     if (lhs.client < rhs.client) return -1;
     if (lhs.client > rhs.client) return 1;
-    if (lhs.state.surface < rhs.state.surface)  return -1;
-    if (lhs.state.surface > rhs.state.surface)  return 1;
+    if (lhs.state.surface < rhs.state.surface) return -1;
+    if (lhs.state.surface > rhs.state.surface) return 1;
     return 0;
 }
 
-static inline
-int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
+static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) {
     return compare_type(lhs.token, rhs.token);
 }
 
 }; // namespace android
 
 #endif // ANDROID_SF_LAYER_STATE_H
-
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 34708c7..4907866 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -200,22 +200,21 @@
                 float alpha);
         Transaction& setMatrix(const sp<SurfaceControl>& sc,
                 float dsdx, float dtdx, float dtdy, float dsdy);
-        Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
-        Transaction& setFinalCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setFinalCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
         Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
         // Defers applying any changes made in this transaction until the Layer
         // identified by handle reaches the given frameNumber. If the Layer identified
         // by handle is removed, then we will apply this transaction regardless of
         // what frame number has been reached.
-        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
-                const sp<IBinder>& handle,
-                uint64_t frameNumber);
-        // A variant of deferTransactionUntil which identifies the Layer we wait for by
+        Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+                                                  const sp<IBinder>& handle, uint64_t frameNumber);
+        // A variant of deferTransactionUntil_legacy which identifies the Layer we wait for by
         // Surface instead of Handle. Useful for clients which may not have the
         // SurfaceControl for some of their Surfaces. Otherwise behaves identically.
-        Transaction& deferTransactionUntil(const sp<SurfaceControl>& sc,
-                const sp<Surface>& barrierSurface,
-                uint64_t frameNumber);
+        Transaction& deferTransactionUntil_legacy(const sp<SurfaceControl>& sc,
+                                                  const sp<Surface>& barrierSurface,
+                                                  uint64_t frameNumber);
         // Reparents all children of this layer to the new parent handle.
         Transaction& reparentChildren(const sp<SurfaceControl>& sc,
                 const sp<IBinder>& newParentHandle);
@@ -228,6 +227,20 @@
 
         Transaction& setColor(const sp<SurfaceControl>& sc, const half3& color);
 
+        Transaction& setTransform(const sp<SurfaceControl>& sc, uint32_t transform);
+        Transaction& setTransformToDisplayInverse(const sp<SurfaceControl>& sc,
+                                                  bool transformToDisplayInverse);
+        Transaction& setCrop(const sp<SurfaceControl>& sc, const Rect& crop);
+        Transaction& setBuffer(const sp<SurfaceControl>& sc, const sp<GraphicBuffer>& buffer);
+        Transaction& setAcquireFence(const sp<SurfaceControl>& sc, const sp<Fence>& fence);
+        Transaction& setDataspace(const sp<SurfaceControl>& sc, ui::Dataspace dataspace);
+        Transaction& setHdrMetadata(const sp<SurfaceControl>& sc, const HdrMetadata& hdrMetadata);
+        Transaction& setSurfaceDamageRegion(const sp<SurfaceControl>& sc,
+                                            const Region& surfaceDamageRegion);
+        Transaction& setApi(const sp<SurfaceControl>& sc, int32_t api);
+        Transaction& setSidebandStream(const sp<SurfaceControl>& sc,
+                                       const sp<NativeHandle>& sidebandStream);
+
         // Detaches all child surfaces (and their children recursively)
         // from their SurfaceControl.
         // The child SurfaceControls will not throw exceptions or return errors,
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index e247398..2a962b5 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -945,3 +945,35 @@
   EXPECT_EQ(b1_id, p2_id);
   EXPECT_TRUE(IsBufferGained(p2->buffer_state()));
 }
+
+TEST_F(LibBufferHubTest, TestDuplicateDetachedBuffer) {
+  auto b1 = DetachedBuffer::Create(kWidth, kHeight, kLayerCount, kFormat,
+                                   kUsage, kUserMetadataSize);
+  int b1_id = b1->id();
+  EXPECT_TRUE(b1->IsValid());
+
+  auto status_or_handle = b1->Duplicate();
+  EXPECT_TRUE(status_or_handle);
+
+  // The detached buffer should still be valid.
+  EXPECT_TRUE(b1->IsConnected());
+  EXPECT_TRUE(b1->IsValid());
+
+  // Gets the channel handle for the duplicated buffer.
+  LocalChannelHandle h2 = status_or_handle.take();
+  EXPECT_TRUE(h2.valid());
+
+  std::unique_ptr<DetachedBuffer> b2 = DetachedBuffer::Import(std::move(h2));
+  EXPECT_FALSE(h2.valid());
+  ASSERT_TRUE(b2 != nullptr);
+  int b2_id = b2->id();
+
+  // The duplicated buffer should inherit the same buffer id.
+  EXPECT_EQ(b1_id, b2_id);
+
+  // Promote the detached buffer should fail as b1 is no longer the exclusive
+  // owner of the buffer..
+  status_or_handle = b1->Promote();
+  EXPECT_FALSE(status_or_handle.ok());
+  EXPECT_EQ(status_or_handle.error(), EINVAL);
+}
diff --git a/libs/vr/libbufferhub/detached_buffer.cpp b/libs/vr/libbufferhub/detached_buffer.cpp
index 6fae16d..60f11e2 100644
--- a/libs/vr/libbufferhub/detached_buffer.cpp
+++ b/libs/vr/libbufferhub/detached_buffer.cpp
@@ -104,6 +104,20 @@
   return status_or_handle;
 }
 
+Status<LocalChannelHandle> DetachedBuffer::Duplicate() {
+  ATRACE_NAME("DetachedBuffer::Duplicate");
+  ALOGD_IF(TRACE, "DetachedBuffer::Duplicate: id=%d.", id_);
+
+  auto status_or_handle =
+      client_.InvokeRemoteMethod<DetachedBufferRPC::Duplicate>();
+
+  if (!status_or_handle.ok()) {
+    ALOGE("DetachedBuffer::Duplicate: Failed to duplicate buffer (id=%d): %s.",
+          id_, status_or_handle.GetErrorMessage().c_str());
+  }
+  return status_or_handle;
+}
+
 sp<GraphicBuffer> DetachedBuffer::TakeGraphicBuffer() {
   if (!client_.IsValid() || !buffer_.buffer()) {
     ALOGE("DetachedBuffer::TakeGraphicBuffer: Invalid buffer.");
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
new file mode 100644
index 0000000..8b2bf91
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_defs.h
@@ -0,0 +1,89 @@
+#ifndef ANDROID_DVR_BUFFER_HUB_DEFS_H_
+#define ANDROID_DVR_BUFFER_HUB_DEFS_H_
+
+#include <dvr/dvr_api.h>
+#include <hardware/gralloc.h>
+
+#include <atomic>
+
+namespace android {
+namespace dvr {
+
+namespace BufferHubDefs {
+
+static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
+static constexpr uint32_t kMetadataUsage =
+    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+// Single producuer multiple (up to 63) consumers ownership signal.
+// 64-bit atomic unsigned int.
+//
+// MSB           LSB
+//  |             |
+//  v             v
+// [P|C62|...|C1|C0]
+// Gain'ed state:     [0|..|0|0] -> Exclusively Writable.
+// Post'ed state:     [1|..|0|0]
+// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
+// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
+static constexpr uint64_t kProducerStateBit = 1ULL << 63;
+static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
+
+static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
+                                     uint64_t clear_mask, uint64_t set_mask) {
+  uint64_t old_state;
+  uint64_t new_state;
+  do {
+    old_state = buffer_state->load();
+    new_state = (old_state & ~clear_mask) | set_mask;
+  } while (!buffer_state->compare_exchange_weak(old_state, new_state));
+}
+
+static inline bool IsBufferGained(uint64_t state) { return state == 0; }
+
+static inline bool IsBufferPosted(uint64_t state,
+                                  uint64_t consumer_bit = kConsumerStateMask) {
+  return (state & kProducerStateBit) && !(state & consumer_bit);
+}
+
+static inline bool IsBufferAcquired(uint64_t state) {
+  return (state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline bool IsBufferReleased(uint64_t state) {
+  return !(state & kProducerStateBit) && (state & kConsumerStateMask);
+}
+
+static inline uint64_t FindNextClearedBit(uint64_t bits) {
+  return ~bits - (~bits & (~bits - 1));
+}
+
+static inline uint64_t FindFirstClearedBit() {
+  return FindNextClearedBit(kProducerStateBit);
+}
+
+struct __attribute__((packed, aligned(8))) MetadataHeader {
+  // Internal data format, which can be updated as long as the size, padding and
+  // field alignment of the struct is consistent within the same ABI. As this
+  // part is subject for future updates, it's not stable cross Android version,
+  // so don't have it visible from outside of the Android platform (include Apps
+  // and vendor HAL).
+  std::atomic<uint64_t> buffer_state;
+  std::atomic<uint64_t> fence_state;
+  uint64_t queue_index;
+
+  // Public data format, which should be updated with caution. See more details
+  // in dvr_api.h
+  DvrNativeBufferMetadata metadata;
+};
+
+static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
+static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
+
+}  // namespace BufferHubDefs
+
+}  // namespace dvr
+}  // namespace android
+
+
+#endif  // ANDROID_DVR_BUFFER_HUB_DEFS_H_
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index 088a235..e163216 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -1,11 +1,11 @@
 #ifndef ANDROID_DVR_BUFFERHUB_RPC_H_
 #define ANDROID_DVR_BUFFERHUB_RPC_H_
 
+#include "buffer_hub_defs.h"
+
 #include <cutils/native_handle.h>
-#include <sys/types.h>
 #include <ui/BufferQueueDefs.h>
 
-#include <dvr/dvr_api.h>
 #include <pdx/channel_handle.h>
 #include <pdx/file_handle.h>
 #include <pdx/rpc/remote_method.h>
@@ -15,71 +15,6 @@
 namespace android {
 namespace dvr {
 
-namespace BufferHubDefs {
-
-static constexpr uint32_t kMetadataFormat = HAL_PIXEL_FORMAT_BLOB;
-static constexpr uint32_t kMetadataUsage =
-    GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
-
-// Single producuer multiple (up to 63) consumers ownership signal.
-// 64-bit atomic unsigned int.
-//
-// MSB           LSB
-//  |             |
-//  v             v
-// [P|C62|...|C1|C0]
-// Gain'ed state:     [0|..|0|0] -> Exclusively Writable.
-// Post'ed state:     [1|..|0|0]
-// Acquired'ed state: [1|..|X|X] -> At least one bit is set in lower 63 bits
-// Released'ed state: [0|..|X|X] -> At least one bit is set in lower 63 bits
-static constexpr uint64_t kProducerStateBit = 1ULL << 63;
-static constexpr uint64_t kConsumerStateMask = (1ULL << 63) - 1;
-
-static inline void ModifyBufferState(std::atomic<uint64_t>* buffer_state,
-                                     uint64_t clear_mask, uint64_t set_mask) {
-  uint64_t old_state;
-  uint64_t new_state;
-  do {
-    old_state = buffer_state->load();
-    new_state = (old_state & ~clear_mask) | set_mask;
-  } while (!buffer_state->compare_exchange_weak(old_state, new_state));
-}
-
-static inline bool IsBufferGained(uint64_t state) { return state == 0; }
-
-static inline bool IsBufferPosted(uint64_t state,
-                                  uint64_t consumer_bit = kConsumerStateMask) {
-  return (state & kProducerStateBit) && !(state & consumer_bit);
-}
-
-static inline bool IsBufferAcquired(uint64_t state) {
-  return (state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-static inline bool IsBufferReleased(uint64_t state) {
-  return !(state & kProducerStateBit) && (state & kConsumerStateMask);
-}
-
-struct __attribute__((packed, aligned(8))) MetadataHeader {
-  // Internal data format, which can be updated as long as the size, padding and
-  // field alignment of the struct is consistent within the same ABI. As this
-  // part is subject for future updates, it's not stable cross Android version,
-  // so don't have it visible from outside of the Android platform (include Apps
-  // and vendor HAL).
-  std::atomic<uint64_t> buffer_state;
-  std::atomic<uint64_t> fence_state;
-  uint64_t queue_index;
-
-  // Public data format, which should be updated with caution. See more details
-  // in dvr_api.h
-  DvrNativeBufferMetadata metadata;
-};
-
-static_assert(sizeof(MetadataHeader) == 128, "Unexpected MetadataHeader size");
-static constexpr size_t kMetadataHeaderSize = sizeof(MetadataHeader);
-
-}  // namespace BufferHubDefs
-
 template <typename FileHandleType>
 class NativeBufferHandle {
  public:
@@ -450,6 +385,7 @@
     kOpCreate = kOpDetachedBufferBase,
     kOpImport,
     kOpPromote,
+    kOpDuplicate,
   };
 
  public:
@@ -459,8 +395,9 @@
                          size_t user_metadata_size));
   PDX_REMOTE_METHOD(Import, kOpImport, BufferDescription<LocalHandle>(Void));
   PDX_REMOTE_METHOD(Promote, kOpPromote, LocalChannelHandle(Void));
+  PDX_REMOTE_METHOD(Duplicate, kOpDuplicate, LocalChannelHandle(Void));
 
-  PDX_REMOTE_API(API, Create, Promote);
+  PDX_REMOTE_API(API, Create, Import, Promote, Duplicate);
 };
 
 }  // namespace dvr
diff --git a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
index 6d0b502..376b53e 100644
--- a/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
+++ b/libs/vr/libbufferhub/include/private/dvr/detached_buffer.h
@@ -57,6 +57,9 @@
   // return. Further IPCs towards this channel will return error.
   pdx::Status<pdx::LocalChannelHandle> Promote();
 
+  // Creates a DetachedBuffer from an existing one.
+  pdx::Status<pdx::LocalChannelHandle> Duplicate();
+
   // Takes the underlying graphic buffer out of this DetachedBuffer. This call
   // immediately invalidates this DetachedBuffer object and transfers the
   // underlying pdx::LocalChannelHandle into the GraphicBuffer.
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index b919710..3fa1311 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -91,6 +91,8 @@
     srcs: [
         "BufferLayer.cpp",
         "BufferLayerConsumer.cpp",
+        "BufferQueueLayer.cpp",
+        "BufferStateLayer.cpp",
         "Client.cpp",
         "ColorLayer.cpp",
         "ContainerLayer.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 37f4b0f..e724666 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -53,22 +53,18 @@
 BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
                          uint32_t w, uint32_t h, uint32_t flags)
       : Layer(flinger, client, name, w, h, flags),
-        mConsumer(nullptr),
-        mTextureName(UINT32_MAX),
-        mFormat(PIXEL_FORMAT_NONE),
+        mTextureName(mFlinger->getNewTexture()),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mBufferLatched(false),
-        mPreviousFrameNumber(0),
-        mUpdateTexImageFailed(false),
         mRefreshPending(false) {
     ALOGV("Creating Layer %s", name.string());
 
-    mTextureName = mFlinger->getNewTexture();
     mTexture.init(Texture::TEXTURE_EXTERNAL, mTextureName);
 
-    if (flags & ISurfaceComposerClient::eNonPremultiplied) mPremultipliedAlpha = false;
+    mPremultipliedAlpha = !(flags & ISurfaceComposerClient::eNonPremultiplied);
 
-    mCurrentState.requested = mCurrentState.active;
+    mPotentialCursor = flags & ISurfaceComposerClient::eCursorWindow;
+    mProtectedByApp = flags & ISurfaceComposerClient::eProtectedByApp;
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
@@ -89,7 +85,7 @@
     if (mFlinger->mForceFullDamage) {
         surfaceDamageRegion = Region::INVALID_REGION;
     } else {
-        surfaceDamageRegion = mConsumer->getSurfaceDamage();
+        surfaceDamageRegion = getDrawingSurfaceDamage();
     }
 }
 
@@ -97,9 +93,16 @@
     surfaceDamageRegion.clear();
 }
 
-bool BufferLayer::isProtected() const {
-    const sp<GraphicBuffer>& buffer(mActiveBuffer);
-    return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+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)) {
+        return false;
+    }
+
+    // if the layer has the opaque flag, then we're always opaque,
+    // otherwise we use the current buffer's format.
+    return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat());
 }
 
 bool BufferLayer::isVisible() const {
@@ -111,30 +114,6 @@
     return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE;
 }
 
-status_t BufferLayer::setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags) {
-    uint32_t const maxSurfaceDims =
-            min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
-
-    // never allow a surface larger than what our underlying GL implementation
-    // can handle.
-    if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
-        ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
-        return BAD_VALUE;
-    }
-
-    mFormat = format;
-
-    mPotentialCursor = (flags & ISurfaceComposerClient::eCursorWindow) ? true : false;
-    mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
-    mCurrentOpacity = getOpacityForFormat(format);
-
-    mConsumer->setDefaultBufferSize(w, h);
-    mConsumer->setDefaultBufferFormat(format);
-    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-
-    return NO_ERROR;
-}
-
 static constexpr mat4 inverseOrientation(uint32_t transform) {
     const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1);
     const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1);
@@ -157,7 +136,7 @@
  * onDraw will draw the current layer onto the presentable buffer
  */
 void BufferLayer::onDraw(const RenderArea& renderArea, const Region& clip,
-                         bool useIdentityTransform) const {
+                         bool useIdentityTransform) {
     ATRACE_CALL();
 
     CompositionInfo& compositionInfo = getBE().compositionInfo;
@@ -191,7 +170,7 @@
 
     // Bind the current buffer to the GL texture, and wait for it to be
     // ready for us to draw into.
-    status_t err = mConsumer->bindTextureImage();
+    status_t err = bindTextureImage();
     if (err != NO_ERROR) {
         ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
         // Go ahead and draw the buffer anyway; no matter what we do the screen
@@ -208,8 +187,8 @@
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
-        mConsumer->setFilteringEnabled(useFiltering);
-        mConsumer->getTransformMatrix(textureMatrix);
+        setFilteringEnabled(useFiltering);
+        getDrawingTransformMatrix(textureMatrix);
 
         if (getTransformToDisplayInverse()) {
             /*
@@ -253,7 +232,7 @@
     engine.disableTexturing();
 }
 
-void BufferLayer::drawNow(const RenderArea& renderArea, bool useIdentityTransform) const {
+void BufferLayer::drawNow(const RenderArea& renderArea, bool useIdentityTransform) {
     CompositionInfo& compositionInfo = getBE().compositionInfo;
     auto& engine(mFlinger->getRenderEngine());
 
@@ -270,360 +249,11 @@
     engine.setSourceY410BT2020(false);
 }
 
-void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    mConsumer->setReleaseFence(releaseFence);
-}
-
-void BufferLayer::abandon() {
-    mConsumer->abandon();
-}
-
-bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
-    if (mSidebandStreamChanged || mAutoRefresh) {
-        return true;
-    }
-
-    Mutex::Autolock lock(mQueueItemLock);
-    if (mQueueItems.empty()) {
-        return false;
-    }
-    auto timestamp = mQueueItems[0].mTimestamp;
-    nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync);
-
-    // Ignore timestamps more than a second in the future
-    bool isPlausible = timestamp < (expectedPresent + s2ns(1));
-    ALOGW_IF(!isPlausible,
-             "[%s] Timestamp %" PRId64 " seems implausible "
-             "relative to expectedPresent %" PRId64,
-             mName.string(), timestamp, expectedPresent);
-
-    bool isDue = timestamp < expectedPresent;
-    return isDue || !isPlausible;
-}
-
-void BufferLayer::setTransformHint(uint32_t orientation) const {
-    mConsumer->setTransformHint(orientation);
-}
-
-bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
-    if (mBufferLatched) {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
-    }
-    mRefreshPending = false;
-    return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
-}
-bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
-                                    const std::shared_ptr<FenceTime>& presentFence,
-                                    const CompositorTiming& compositorTiming) {
-    // mFrameLatencyNeeded is true when a new frame was latched for the
-    // composition.
-    if (!mFrameLatencyNeeded) return false;
-
-    // Update mFrameEventHistory.
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
-                                              compositorTiming);
-    }
-
-    // Update mFrameTracker.
-    nsecs_t desiredPresentTime = mConsumer->getTimestamp();
-    mFrameTracker.setDesiredPresentTime(desiredPresentTime);
-
-    const std::string layerName(getName().c_str());
-    mTimeStats.setDesiredTime(layerName, mCurrentFrameNumber, desiredPresentTime);
-
-    std::shared_ptr<FenceTime> frameReadyFence = mConsumer->getCurrentFenceTime();
-    if (frameReadyFence->isValid()) {
-        mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
-    } else {
-        // There was no fence for this frame, so assume that it was ready
-        // to be presented at the desired present time.
-        mFrameTracker.setFrameReadyTime(desiredPresentTime);
-    }
-
-    if (presentFence->isValid()) {
-        mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
-        mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
-    } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
-        // The HWC doesn't support present fences, so use the refresh
-        // timestamp instead.
-        const nsecs_t actualPresentTime =
-                mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
-        mTimeStats.setPresentTime(layerName, mCurrentFrameNumber, actualPresentTime);
-        mFrameTracker.setActualPresentTime(actualPresentTime);
-    }
-
-    mFrameTracker.advanceFrame();
-    mFrameLatencyNeeded = false;
-    return true;
-}
-
-std::vector<OccupancyTracker::Segment> BufferLayer::getOccupancyHistory(bool forceFlush) {
-    std::vector<OccupancyTracker::Segment> history;
-    status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
-    if (result != NO_ERROR) {
-        ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
-        return {};
-    }
-    return history;
-}
-
-bool BufferLayer::getTransformToDisplayInverse() const {
-    return mConsumer->getTransformToDisplayInverse();
-}
-
-void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
-    if (!mConsumer->releasePendingBuffer()) {
-        return;
-    }
-
-    auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
-    mReleaseTimeline.updateSignalTimes();
-    mReleaseTimeline.push(releaseFenceTime);
-
-    Mutex::Autolock lock(mFrameEventHistoryMutex);
-    if (mPreviousFrameNumber != 0) {
-        mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
-                                      std::move(releaseFenceTime));
-    }
-}
-
-Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
-    ATRACE_CALL();
-
-    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
-        // mSidebandStreamChanged was true
-        mSidebandStream = mConsumer->getSidebandStream();
-        // replicated in LayerBE until FE/BE is ready to be synchronized
-        getBE().compositionInfo.hwc.sidebandStream = mSidebandStream;
-        if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
-            setTransactionFlags(eTransactionNeeded);
-            mFlinger->setTransactionFlags(eTraversalNeeded);
-        }
-        recomputeVisibleRegions = true;
-
-        const State& s(getDrawingState());
-        return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
-    }
-
-    Region outDirtyRegion;
-    if (mQueuedFrames <= 0 && !mAutoRefresh) {
-        return outDirtyRegion;
-    }
-
-    // if we've already called updateTexImage() without going through
-    // a composition step, we have to skip this layer at this point
-    // because we cannot call updateTeximage() without a corresponding
-    // compositionComplete() call.
-    // we'll trigger an update in onPreComposition().
-    if (mRefreshPending) {
-        return outDirtyRegion;
-    }
-
-    // If the head buffer's acquire fence hasn't signaled yet, return and
-    // try again later
-    if (!headFenceHasSignaled()) {
-        mFlinger->signalLayerUpdate();
-        return outDirtyRegion;
-    }
-
-    // Capture the old state of the layer for comparisons later
-    const State& s(getDrawingState());
-    const bool oldOpacity = isOpaque(s);
-    sp<GraphicBuffer> oldBuffer = mActiveBuffer;
-
-    if (!allTransactionsSignaled()) {
-        mFlinger->signalLayerUpdate();
-        return outDirtyRegion;
-    }
-
-    // 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
-    // buffer mode.
-    bool queuedBuffer = false;
-    LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
-                    getTransformToDisplayInverse(),  mFreezeGeometryUpdates);
-
-    status_t updateResult = mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh,
-                                                      &queuedBuffer, mLastFrameNumberReceived);
-
-    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.
-        mFlinger->signalLayerUpdate();
-        return outDirtyRegion;
-    } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
-        // If the buffer has been rejected, remove it from the shadow queue
-        // and return early
-        if (queuedBuffer) {
-            Mutex::Autolock lock(mQueueItemLock);
-            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
-            mQueueItems.removeAt(0);
-            android_atomic_dec(&mQueuedFrames);
-        }
-        return outDirtyRegion;
-    } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
-        // This can occur if something goes wrong when trying to create the
-        // EGLImage for this buffer. If this happens, the buffer has already
-        // been released, so we need to clean up the queue and bug out
-        // early.
-        if (queuedBuffer) {
-            Mutex::Autolock lock(mQueueItemLock);
-            mQueueItems.clear();
-            android_atomic_and(0, &mQueuedFrames);
-            mTimeStats.clearLayerRecord(getName().c_str());
-        }
-
-        // Once we have hit this state, the shadow queue may no longer
-        // correctly reflect the incoming BufferQueue's contents, so even if
-        // updateTexImage starts working, the only safe course of action is
-        // to continue to ignore updates.
-        mUpdateTexImageFailed = true;
-
-        return outDirtyRegion;
-    }
-
-    if (queuedBuffer) {
-        // Autolock scope
-        auto currentFrameNumber = mConsumer->getFrameNumber();
-
-        Mutex::Autolock lock(mQueueItemLock);
-
-        // Remove any stale buffers that have been dropped during
-        // updateTexImage
-        while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
-            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
-            mQueueItems.removeAt(0);
-            android_atomic_dec(&mQueuedFrames);
-        }
-
-        const std::string layerName(getName().c_str());
-        mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
-        mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
-
-        mQueueItems.removeAt(0);
-    }
-
-    // Decrement the queued-frames count.  Signal another event if we
-    // have more frames pending.
-    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
-        mFlinger->signalLayerUpdate();
-    }
-
-    // update the active buffer
-    mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
-    getBE().compositionInfo.mBuffer = mActiveBuffer;
-    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
-
-    if (mActiveBuffer == nullptr) {
-        // this can only happen if the very first buffer was rejected.
-        return outDirtyRegion;
-    }
-
-    mBufferLatched = true;
-    mPreviousFrameNumber = mCurrentFrameNumber;
-    mCurrentFrameNumber = mConsumer->getFrameNumber();
-
-    {
-        Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
-    }
-
-    mRefreshPending = true;
-    mFrameLatencyNeeded = true;
-    if (oldBuffer == nullptr) {
-        // the first time we receive a buffer, we need to trigger a
-        // geometry invalidation.
-        recomputeVisibleRegions = true;
-    }
-
-    ui::Dataspace dataSpace = mConsumer->getCurrentDataSpace();
-    // treat modern dataspaces as legacy dataspaces whenever possible, until
-    // we can trust the buffer producers
-    switch (dataSpace) {
-        case ui::Dataspace::V0_SRGB:
-            dataSpace = ui::Dataspace::SRGB;
-            break;
-        case ui::Dataspace::V0_SRGB_LINEAR:
-            dataSpace = ui::Dataspace::SRGB_LINEAR;
-            break;
-        case ui::Dataspace::V0_JFIF:
-            dataSpace = ui::Dataspace::JFIF;
-            break;
-        case ui::Dataspace::V0_BT601_625:
-            dataSpace = ui::Dataspace::BT601_625;
-            break;
-        case ui::Dataspace::V0_BT601_525:
-            dataSpace = ui::Dataspace::BT601_525;
-            break;
-        case ui::Dataspace::V0_BT709:
-            dataSpace = ui::Dataspace::BT709;
-            break;
-        default:
-            break;
-    }
-    mCurrentDataSpace = dataSpace;
-
-    Rect crop(mConsumer->getCurrentCrop());
-    const uint32_t transform(mConsumer->getCurrentTransform());
-    const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
-    if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
-        (scalingMode != mCurrentScalingMode)) {
-        mCurrentCrop = crop;
-        mCurrentTransform = transform;
-        mCurrentScalingMode = scalingMode;
-        recomputeVisibleRegions = true;
-    }
-
-    if (oldBuffer != nullptr) {
-        uint32_t bufWidth = mActiveBuffer->getWidth();
-        uint32_t bufHeight = mActiveBuffer->getHeight();
-        if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) {
-            recomputeVisibleRegions = true;
-        }
-    }
-
-    mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
-    if (oldOpacity != isOpaque(s)) {
-        recomputeVisibleRegions = true;
-    }
-
-    // Remove any sync points corresponding to the buffer which was just
-    // latched
-    {
-        Mutex::Autolock lock(mLocalSyncPointMutex);
-        auto point = mLocalSyncPoints.begin();
-        while (point != mLocalSyncPoints.end()) {
-            if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) {
-                // This sync point must have been added since we started
-                // latching. Don't drop it yet.
-                ++point;
-                continue;
-            }
-
-            if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
-                point = mLocalSyncPoints.erase(point);
-            } else {
-                ++point;
-            }
-        }
-    }
-
-    // FIXME: postedRegion should be dirty & bounds
-    Region dirtyRegion(Rect(s.active.w, s.active.h));
-
-    // transform the dirty region to window-manager space
-    outDirtyRegion = (getTransform().transform(dirtyRegion));
-
-    return outDirtyRegion;
-}
-
-void BufferLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
-    mConsumer->setDefaultBufferSize(w, h);
+bool BufferLayer::isHdrY410() const {
+    // 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);
 }
 
 void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
@@ -683,132 +313,282 @@
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
-    const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
+    const HdrMetadata& metadata = getDrawingHdrMetadata();
     error = hwcLayer->setPerFrameMetadata(display->getSupportedPerFrameMetadata(), metadata);
     if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
         ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
-    uint32_t hwcSlot = 0;
-    sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
-
-    auto acquireFence = mConsumer->getCurrentFence();
-    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));
-    }
+    setHwcLayerBuffer(display);
 }
 
-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)) {
-        return false;
+bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
+    if (mBufferLatched) {
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
     }
-
-    // if the layer has the opaque flag, then we're always opaque,
-    // otherwise we use the current buffer's format.
-    return ((s.flags & layer_state_t::eLayerOpaque) != 0) || mCurrentOpacity;
+    mRefreshPending = false;
+    return hasReadyFrame();
 }
 
-void BufferLayer::onFirstRef() {
-    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
-    sp<IGraphicBufferProducer> producer;
-    sp<IGraphicBufferConsumer> consumer;
-    BufferQueue::createBufferQueue(&producer, &consumer, true);
-    mProducer = new MonitoredProducer(producer, mFlinger, this);
+bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+                                    const std::shared_ptr<FenceTime>& presentFence,
+                                    const CompositorTiming& compositorTiming) {
+    // mFrameLatencyNeeded is true when a new frame was latched for the
+    // composition.
+    if (!mFrameLatencyNeeded) return false;
+
+    // Update mFrameEventHistory.
     {
-        // Grab the SF state lock during this since it's the only safe way to access RenderEngine
-        Mutex::Autolock lock(mFlinger->mStateLock);
-        mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName,
-                                            this);
-    }
-    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-    mConsumer->setContentsChangedListener(this);
-    mConsumer->setName(mName);
-
-    if (mFlinger->isLayerTripleBufferingDisabled()) {
-        mProducer->setMaxDequeuedBufferCount(2);
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
+                                              compositorTiming);
     }
 
-    if (const auto display = mFlinger->getDefaultDisplayDevice()) {
-        updateTransformHint(display);
+    // Update mFrameTracker.
+    nsecs_t desiredPresentTime = getDesiredPresentTime();
+    mFrameTracker.setDesiredPresentTime(desiredPresentTime);
+
+    const std::string layerName(getName().c_str());
+    mTimeStats.setDesiredTime(layerName, mCurrentFrameNumber, desiredPresentTime);
+
+    std::shared_ptr<FenceTime> frameReadyFence = getCurrentFenceTime();
+    if (frameReadyFence->isValid()) {
+        mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
+    } else {
+        // There was no fence for this frame, so assume that it was ready
+        // to be presented at the desired present time.
+        mFrameTracker.setFrameReadyTime(desiredPresentTime);
     }
+
+    if (presentFence->isValid()) {
+        mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
+        mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
+    } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
+        // The HWC doesn't support present fences, so use the refresh
+        // timestamp instead.
+        const nsecs_t actualPresentTime =
+                mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+        mTimeStats.setPresentTime(layerName, mCurrentFrameNumber, actualPresentTime);
+        mFrameTracker.setActualPresentTime(actualPresentTime);
+    }
+
+    mFrameTracker.advanceFrame();
+    mFrameLatencyNeeded = false;
+    return true;
 }
 
-// ---------------------------------------------------------------------------
-// Interface implementation for SurfaceFlingerConsumer::ContentsChangedListener
-// ---------------------------------------------------------------------------
+Region BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+    ATRACE_CALL();
 
-void BufferLayer::onFrameAvailable(const BufferItem& item) {
-    // Add this buffer from our internal queue tracker
-    { // Autolock scope
-        Mutex::Autolock lock(mQueueItemLock);
-        mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
-                                                 item.mGraphicBuffer->getHeight(),
-                                                 item.mFrameNumber);
-        // Reset the frame number tracker when we receive the first buffer after
-        // a frame number reset
-        if (item.mFrameNumber == 1) {
-            mLastFrameNumberReceived = 0;
-        }
+    std::optional<Region> sidebandStreamDirtyRegion = latchSidebandStream(recomputeVisibleRegions);
 
-        // Ensure that callbacks are handled in order
-        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
-            if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", mName.string());
-            }
-        }
-
-        mQueueItems.push_back(item);
-        android_atomic_inc(&mQueuedFrames);
-
-        // Wake up any pending callbacks
-        mLastFrameNumberReceived = item.mFrameNumber;
-        mQueueItemCondition.broadcast();
+    if (sidebandStreamDirtyRegion) {
+        return *sidebandStreamDirtyRegion;
     }
 
-    mFlinger->signalLayerUpdate();
-}
+    Region dirtyRegion;
 
-void BufferLayer::onFrameReplaced(const BufferItem& item) {
-    { // Autolock scope
-        Mutex::Autolock lock(mQueueItemLock);
-
-        // Ensure that callbacks are handled in order
-        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
-            if (result != NO_ERROR) {
-                ALOGE("[%s] Timed out waiting on callback", mName.string());
-            }
-        }
-
-        if (mQueueItems.empty()) {
-            ALOGE("Can't replace a frame on an empty queue");
-            return;
-        }
-        mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
-
-        // Wake up any pending callbacks
-        mLastFrameNumberReceived = item.mFrameNumber;
-        mQueueItemCondition.broadcast();
+    if (!hasReadyFrame()) {
+        return dirtyRegion;
     }
-}
 
-void BufferLayer::onSidebandStreamChanged() {
-    if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
-        // mSidebandStreamChanged was false
+    // if we've already called updateTexImage() without going through
+    // a composition step, we have to skip this layer at this point
+    // because we cannot call updateTeximage() without a corresponding
+    // compositionComplete() call.
+    // we'll trigger an update in onPreComposition().
+    if (mRefreshPending) {
+        return dirtyRegion;
+    }
+
+    // If the head buffer's acquire fence hasn't signaled yet, return and
+    // try again later
+    if (!fenceHasSignaled()) {
         mFlinger->signalLayerUpdate();
+        return dirtyRegion;
+    }
+
+    // Capture the old state of the layer for comparisons later
+    const State& s(getDrawingState());
+    const bool oldOpacity = isOpaque(s);
+    sp<GraphicBuffer> oldBuffer = mActiveBuffer;
+
+    if (!allTransactionsSignaled()) {
+        mFlinger->signalLayerUpdate();
+        return dirtyRegion;
+    }
+
+    status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
+    if (err != NO_ERROR) {
+        return dirtyRegion;
+    }
+
+    err = updateActiveBuffer();
+    if (err != NO_ERROR) {
+        return dirtyRegion;
+    }
+
+    mBufferLatched = true;
+
+    err = updateFrameNumber(latchTime);
+    if (err != NO_ERROR) {
+        return dirtyRegion;
+    }
+
+    mRefreshPending = true;
+    mFrameLatencyNeeded = true;
+    if (oldBuffer == nullptr) {
+        // the first time we receive a buffer, we need to trigger a
+        // geometry invalidation.
+        recomputeVisibleRegions = true;
+    }
+
+    ui::Dataspace dataSpace = getDrawingDataSpace();
+    // treat modern dataspaces as legacy dataspaces whenever possible, until
+    // we can trust the buffer producers
+    switch (dataSpace) {
+        case ui::Dataspace::V0_SRGB:
+            dataSpace = ui::Dataspace::SRGB;
+            break;
+        case ui::Dataspace::V0_SRGB_LINEAR:
+            dataSpace = ui::Dataspace::SRGB_LINEAR;
+            break;
+        case ui::Dataspace::V0_JFIF:
+            dataSpace = ui::Dataspace::JFIF;
+            break;
+        case ui::Dataspace::V0_BT601_625:
+            dataSpace = ui::Dataspace::BT601_625;
+            break;
+        case ui::Dataspace::V0_BT601_525:
+            dataSpace = ui::Dataspace::BT601_525;
+            break;
+        case ui::Dataspace::V0_BT709:
+            dataSpace = ui::Dataspace::BT709;
+            break;
+        default:
+            break;
+    }
+    mCurrentDataSpace = dataSpace;
+
+    Rect crop(getDrawingCrop());
+    const uint32_t transform(getDrawingTransform());
+    const uint32_t scalingMode(getDrawingScalingMode());
+    if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
+        (scalingMode != mCurrentScalingMode)) {
+        mCurrentCrop = crop;
+        mCurrentTransform = transform;
+        mCurrentScalingMode = scalingMode;
+        recomputeVisibleRegions = true;
+    }
+
+    if (oldBuffer != nullptr) {
+        uint32_t bufWidth = mActiveBuffer->getWidth();
+        uint32_t bufHeight = mActiveBuffer->getHeight();
+        if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) {
+            recomputeVisibleRegions = true;
+        }
+    }
+
+    if (oldOpacity != isOpaque(s)) {
+        recomputeVisibleRegions = true;
+    }
+
+    // Remove any sync points corresponding to the buffer which was just
+    // latched
+    {
+        Mutex::Autolock lock(mLocalSyncPointMutex);
+        auto point = mLocalSyncPoints.begin();
+        while (point != mLocalSyncPoints.end()) {
+            if (!(*point)->frameIsAvailable() || !(*point)->transactionIsApplied()) {
+                // This sync point must have been added since we started
+                // latching. Don't drop it yet.
+                ++point;
+                continue;
+            }
+
+            if ((*point)->getFrameNumber() <= mCurrentFrameNumber) {
+                point = mLocalSyncPoints.erase(point);
+            } else {
+                ++point;
+            }
+        }
+    }
+
+    // FIXME: postedRegion should be dirty & bounds
+    // transform the dirty region to window-manager space
+    return getTransform().transform(Region(Rect(getActiveWidth(s), getActiveHeight(s))));
+}
+
+// transaction
+void BufferLayer::notifyAvailableFrames() {
+    auto headFrameNumber = getHeadFrameNumber();
+    bool headFenceSignaled = fenceHasSignaled();
+    Mutex::Autolock lock(mLocalSyncPointMutex);
+    for (auto& point : mLocalSyncPoints) {
+        if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+            point->setFrameAvailable();
+        }
     }
 }
 
-bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
-    return mNeedsFiltering || renderArea.needsFiltering();
+bool BufferLayer::hasReadyFrame() const {
+    return hasDrawingBuffer() || getSidebandStreamChanged() || getAutoRefresh();
+}
+
+uint32_t BufferLayer::getEffectiveScalingMode() const {
+    if (mOverrideScalingMode >= 0) {
+        return mOverrideScalingMode;
+    }
+
+    return mCurrentScalingMode;
+}
+
+bool BufferLayer::isProtected() const {
+    const sp<GraphicBuffer>& buffer(mActiveBuffer);
+    return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+}
+
+bool BufferLayer::latchUnsignaledBuffers() {
+    static bool propertyLoaded = false;
+    static bool latch = false;
+    static std::mutex mutex;
+    std::lock_guard<std::mutex> lock(mutex);
+    if (!propertyLoaded) {
+        char value[PROPERTY_VALUE_MAX] = {};
+        property_get("debug.sf.latch_unsignaled", value, "0");
+        latch = atoi(value);
+        propertyLoaded = true;
+    }
+    return latch;
+}
+
+// h/w composer set-up
+bool BufferLayer::allTransactionsSignaled() {
+    auto headFrameNumber = getHeadFrameNumber();
+    bool matchingFramesFound = false;
+    bool allTransactionsApplied = true;
+    Mutex::Autolock lock(mLocalSyncPointMutex);
+
+    for (auto& point : mLocalSyncPoints) {
+        if (point->getFrameNumber() > headFrameNumber) {
+            break;
+        }
+        matchingFramesFound = true;
+
+        if (!point->frameIsAvailable()) {
+            // We haven't notified the remote layer that the frame for
+            // this point is available yet. Notify it now, and then
+            // abort this attempt to latch.
+            point->setFrameAvailable();
+            allTransactionsApplied = false;
+            break;
+        }
+
+        allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
+    }
+    return !matchingFramesFound || allTransactionsApplied;
 }
 
 // As documented in libhardware header, formats in the range
@@ -833,11 +613,8 @@
     return true;
 }
 
-bool BufferLayer::isHdrY410() const {
-    // pixel format is HDR Y410 masquerading as RGBA_1010102
-    return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
-            mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
-            getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
+bool BufferLayer::needsFiltering(const RenderArea& renderArea) const {
+    return mNeedsFiltering || renderArea.needsFiltering();
 }
 
 void BufferLayer::drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const {
@@ -864,9 +641,10 @@
 
     Transform t = getTransform();
     Rect win = bounds;
-    if (!s.finalCrop.isEmpty()) {
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
         win = t.transform(win);
-        if (!win.intersect(s.finalCrop, &win)) {
+        if (!win.intersect(finalCrop, &win)) {
             win.clear();
         }
         win = t.inverse().transform(win);
@@ -875,10 +653,10 @@
         }
     }
 
-    float left = float(win.left) / float(s.active.w);
-    float top = float(win.top) / float(s.active.h);
-    float right = float(win.right) / float(s.active.w);
-    float bottom = float(win.bottom) / float(s.active.h);
+    float left = float(win.left) / float(getActiveWidth(s));
+    float top = float(win.top) / float(getActiveHeight(s));
+    float right = float(win.right) / float(getActiveWidth(s));
+    float bottom = float(win.bottom) / float(getActiveHeight(s));
 
     // TODO: we probably want to generate the texture coords with the mesh
     // here we assume that we only have 4 vertices
@@ -903,115 +681,14 @@
     engine.setSourceY410BT2020(false);
 }
 
-uint32_t BufferLayer::getProducerStickyTransform() const {
-    int producerStickyTransform = 0;
-    int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
-    if (ret != OK) {
-        ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
-              strerror(-ret), ret);
-        return 0;
-    }
-    return static_cast<uint32_t>(producerStickyTransform);
-}
-
-bool BufferLayer::latchUnsignaledBuffers() {
-    static bool propertyLoaded = false;
-    static bool latch = false;
-    static std::mutex mutex;
-    std::lock_guard<std::mutex> lock(mutex);
-    if (!propertyLoaded) {
-        char value[PROPERTY_VALUE_MAX] = {};
-        property_get("debug.sf.latch_unsignaled", value, "0");
-        latch = atoi(value);
-        propertyLoaded = true;
-    }
-    return latch;
-}
-
 uint64_t BufferLayer::getHeadFrameNumber() const {
-    Mutex::Autolock lock(mQueueItemLock);
-    if (!mQueueItems.empty()) {
-        return mQueueItems[0].mFrameNumber;
+    if (hasDrawingBuffer()) {
+        return getFrameNumber();
     } else {
         return mCurrentFrameNumber;
     }
 }
 
-bool BufferLayer::headFenceHasSignaled() const {
-    if (latchUnsignaledBuffers()) {
-        return true;
-    }
-
-    Mutex::Autolock lock(mQueueItemLock);
-    if (mQueueItems.empty()) {
-        return true;
-    }
-    if (mQueueItems[0].mIsDroppable) {
-        // Even though this buffer's fence may not have signaled yet, it could
-        // be replaced by another buffer before it has a chance to, which means
-        // that it's possible to get into a situation where a buffer is never
-        // able to be latched. To avoid this, grab this buffer anyway.
-        return true;
-    }
-    return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
-}
-
-uint32_t BufferLayer::getEffectiveScalingMode() const {
-    if (mOverrideScalingMode >= 0) {
-        return mOverrideScalingMode;
-    }
-    return mCurrentScalingMode;
-}
-
-// ----------------------------------------------------------------------------
-// transaction
-// ----------------------------------------------------------------------------
-
-void BufferLayer::notifyAvailableFrames() {
-    auto headFrameNumber = getHeadFrameNumber();
-    bool headFenceSignaled = headFenceHasSignaled();
-    Mutex::Autolock lock(mLocalSyncPointMutex);
-    for (auto& point : mLocalSyncPoints) {
-        if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
-            point->setFrameAvailable();
-        }
-    }
-}
-
-sp<IGraphicBufferProducer> BufferLayer::getProducer() const {
-    return mProducer;
-}
-
-// ---------------------------------------------------------------------------
-// h/w composer set-up
-// ---------------------------------------------------------------------------
-
-bool BufferLayer::allTransactionsSignaled() {
-    auto headFrameNumber = getHeadFrameNumber();
-    bool matchingFramesFound = false;
-    bool allTransactionsApplied = true;
-    Mutex::Autolock lock(mLocalSyncPointMutex);
-
-    for (auto& point : mLocalSyncPoints) {
-        if (point->getFrameNumber() > headFrameNumber) {
-            break;
-        }
-        matchingFramesFound = true;
-
-        if (!point->frameIsAvailable()) {
-            // We haven't notified the remote layer that the frame for
-            // this point is available yet. Notify it now, and then
-            // abort this attempt to latch.
-            point->setFrameAvailable();
-            allTransactionsApplied = false;
-            break;
-        }
-
-        allTransactionsApplied = allTransactionsApplied && point->transactionIsApplied();
-    }
-    return !matchingFramesFound || allTransactionsApplied;
-}
-
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 0886f17..13f4e83 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -47,152 +47,142 @@
 
 namespace android {
 
-/*
- * A new BufferQueue and a new BufferLayerConsumer are created when the
- * BufferLayer is first referenced.
- *
- * This also implements onFrameAvailable(), which notifies SurfaceFlinger
- * that new data has arrived.
- */
-class BufferLayer : public Layer, public BufferLayerConsumer::ContentsChangedListener {
+class BufferLayer : public Layer {
 public:
     BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
                 uint32_t h, uint32_t flags);
 
     ~BufferLayer() override;
 
-    // If we have received a new buffer this frame, we will pass its surface
-    // damage down to hardware composer. Otherwise, we must send a region with
-    // one empty rect.
-    void useSurfaceDamage();
-    void useEmptyDamage();
-
     // -----------------------------------------------------------------------
     // Overriden from Layer
     // -----------------------------------------------------------------------
-
-    /*
-     * getTypeId - Provide unique string for each class type in the Layer
-     * hierarchy
-     */
-    const char* getTypeId() const override { return "BufferLayer"; }
-
-    /*
-     * isProtected - true if the layer may contain protected content in the
-     * GRALLOC_USAGE_PROTECTED sense.
-     */
-    bool isProtected() const;
-
-    /*
-     * isVisible - true if this layer is visible, false otherwise
-     */
-    bool isVisible() const override;
-
-    /*
-     * isFixedSize - true if content has a fixed size
-     */
-    bool isFixedSize() const override;
-
-    // the this layer's size and format
-    status_t setBuffers(uint32_t w, uint32_t h, PixelFormat format, uint32_t flags);
-
-    /*
-     * onDraw - draws the surface.
-     */
-    void onDraw(const RenderArea& renderArea, const Region& clip,
-                bool useIdentityTransform) const override;
-    void drawNow(const RenderArea& renderArea, bool useIdentityTransform) const;
-
-    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
-
-    void abandon() override;
-    bool shouldPresentNow(const DispSync& dispSync) const override;
-    void setTransformHint(uint32_t orientation) const override;
-    bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
-                           const std::shared_ptr<FenceTime>& presentFence,
-                           const CompositorTiming& compositorTiming) override;
-    std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
-    bool getTransformToDisplayInverse() const override;
-
 public:
-    bool onPreComposition(nsecs_t refreshStartTime) override;
+    // If we have received a new buffer this frame, we will pass its surface
+    // damage down to hardware composer. Otherwise, we must send a region with
+    // one empty rect.
+    void useSurfaceDamage() override;
+    void useEmptyDamage() override;
 
-    // If a buffer was replaced this frame, release the former buffer
-    void releasePendingBuffer(nsecs_t dequeueReadyTime);
-
-    /*
-     * latchBuffer - called each time the screen is redrawn and returns whether
-     * 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.
-     */
-    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
-    bool isBufferLatched() const override { return mRefreshPending; }
-    void setDefaultBufferSize(uint32_t w, uint32_t h) override;
-
-    bool isHdrY410() const override;
-
-    void setPerFrameData(const sp<const DisplayDevice>& display) override;
+    // getTypeId - Provide unique string for each class type in the Layer
+    // hierarchy
+    const char* getTypeId() const override { return "BufferLayer"; }
 
     bool isOpaque(const Layer::State& s) const override;
 
-private:
-    void onFirstRef() override;
+    // isVisible - true if this layer is visible, false otherwise
+    bool isVisible() const override;
 
-    // Interface implementation for
-    // BufferLayerConsumer::ContentsChangedListener
-    void onFrameAvailable(const BufferItem& item) override;
-    void onFrameReplaced(const BufferItem& item) override;
-    void onSidebandStreamChanged() override;
+    // isFixedSize - true if content has a fixed size
+    bool isFixedSize() const override;
 
-    // needsLinearFiltering - true if this surface's state requires filtering
-    bool needsFiltering(const RenderArea& renderArea) const;
+    // onDraw - draws the surface.
+    void onDraw(const RenderArea& renderArea, const Region& clip,
+                bool useIdentityTransform) override;
+    void drawNow(const RenderArea& renderArea, bool useIdentityTransform);
 
-    static bool getOpacityForFormat(uint32_t format);
+    bool isHdrY410() const override;
 
-    // drawing
-    void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
+    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
 
-    // Temporary - Used only for LEGACY camera mode.
-    uint32_t getProducerStickyTransform() const;
+    bool onPreComposition(nsecs_t refreshStartTime) override;
+    bool onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
+                           const std::shared_ptr<FenceTime>& presentFence,
+                           const CompositorTiming& compositorTiming) override;
 
-    // Loads the corresponding system property once per process
-    static bool latchUnsignaledBuffers();
+    // latchBuffer - called each time the screen is redrawn and returns whether
+    // 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.
+    Region latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
 
-    uint64_t getHeadFrameNumber() const;
-    bool headFenceHasSignaled() const;
+    bool isBufferLatched() const override { return mRefreshPending; }
+
+    void notifyAvailableFrames() override;
+
+    bool hasReadyFrame() const override;
 
     // Returns the current scaling mode, unless mOverrideScalingMode
     // is set, in which case, it returns mOverrideScalingMode
     uint32_t getEffectiveScalingMode() const override;
+    // -----------------------------------------------------------------------
+
+    // -----------------------------------------------------------------------
+    // Functions that must be implemented by derived classes
+    // -----------------------------------------------------------------------
+private:
+    virtual bool fenceHasSignaled() const = 0;
+
+    virtual nsecs_t getDesiredPresentTime() = 0;
+    virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
+
+    virtual void getDrawingTransformMatrix(float *matrix) = 0;
+    virtual uint32_t getDrawingTransform() const = 0;
+    virtual ui::Dataspace getDrawingDataSpace() const = 0;
+    virtual Rect getDrawingCrop() const = 0;
+    virtual uint32_t getDrawingScalingMode() const = 0;
+    virtual Region getDrawingSurfaceDamage() const = 0;
+    virtual const HdrMetadata& getDrawingHdrMetadata() const = 0;
+    virtual int getDrawingApi() const = 0;
+    virtual PixelFormat getPixelFormat() const = 0;
+
+    virtual uint64_t getFrameNumber() const = 0;
+
+    virtual bool getAutoRefresh() const = 0;
+    virtual bool getSidebandStreamChanged() const = 0;
+
+    virtual std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) = 0;
+
+    virtual bool hasDrawingBuffer() const = 0;
+
+    virtual void setFilteringEnabled(bool enabled) = 0;
+
+    virtual status_t bindTextureImage() const = 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(const sp<const DisplayDevice>& display) = 0;
+
+    // -----------------------------------------------------------------------
 
 public:
-    void notifyAvailableFrames() override;
+    // isProtected - true if the layer may contain protected content in the
+    // GRALLOC_USAGE_PROTECTED sense.
+    bool isProtected() const;
 
-    PixelFormat getPixelFormat() const override { return mFormat; }
-    sp<IGraphicBufferProducer> getProducer() const;
-
-private:
-    sp<BufferLayerConsumer> mConsumer;
+protected:
+    // Loads the corresponding system property once per process
+    static bool latchUnsignaledBuffers();
 
     // Check all of the local sync points to ensure that all transactions
     // which need to have been applied prior to the frame which is about to
     // be latched have signaled
     bool allTransactionsSignaled();
-    sp<IGraphicBufferProducer> mProducer;
 
-    // constants
-    uint32_t mTextureName; // from GLES
-    PixelFormat mFormat;
+    static bool getOpacityForFormat(uint32_t format);
 
-    // main thread
+    // from GLES
+    const uint32_t mTextureName;
+
+private:
+    // needsLinearFiltering - true if this surface's state requires filtering
+    bool needsFiltering(const RenderArea& renderArea) const;
+
+    // drawing
+    void drawWithOpenGL(const RenderArea& renderArea, bool useIdentityTransform) const;
+
+    uint64_t getHeadFrameNumber() const;
+
     uint32_t mCurrentScalingMode;
-    bool mBufferLatched = false;   // TODO: Use mActiveBuffer?
-    uint64_t mPreviousFrameNumber; // Only accessed on the main thread.
+
+    // main thread.
+    bool mBufferLatched; // TODO: Use mActiveBuffer?
+
     // The texture used to draw the layer in GLES composition mode
     mutable Texture mTexture;
 
-    bool mUpdateTexImageFailed; // This is only accessed on the main thread.
     bool mRefreshPending;
 };
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index d231790..8788d47 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -40,7 +40,6 @@
 #include <gui/SurfaceComposerClient.h>
 
 #include <private/gui/ComposerService.h>
-#include <private/gui/SyncFeatures.h>
 
 #include <utils/Log.h>
 #include <utils/String8.h>
@@ -206,7 +205,7 @@
         return err;
     }
 
-    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
+    if (mRE.useNativeFenceSync()) {
         // Bind the new buffer to the GL texture.
         //
         // Older devices require the "implicit" synchronization provided
@@ -374,7 +373,7 @@
     BLC_LOGV("syncForReleaseLocked");
 
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        if (SyncFeatures::getInstance().useNativeFenceSync()) {
+        if (mRE.useNativeFenceSync()) {
             base::unique_fd fenceFd = mRE.flush();
             if (fenceFd == -1) {
                 BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
@@ -512,7 +511,7 @@
     }
 
     if (mCurrentFence->isValid()) {
-        if (SyncFeatures::getInstance().useWaitSync()) {
+        if (mRE.useWaitSync()) {
             base::unique_fd fenceFd(mCurrentFence->dup());
             if (fenceFd == -1) {
                 BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
new file mode 100644
index 0000000..6c339b7
--- /dev/null
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2018 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 "BufferQueueLayer.h"
+#include "LayerRejecter.h"
+#include "clz.h"
+
+#include <system/window.h>
+
+namespace android {
+
+BufferQueueLayer::BufferQueueLayer(SurfaceFlinger* flinger, const sp<Client>& client,
+                                   const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+      : BufferLayer(flinger, client, name, w, h, flags),
+        mConsumer(nullptr),
+        mProducer(nullptr),
+        mFormat(PIXEL_FORMAT_NONE),
+        mPreviousFrameNumber(0),
+        mUpdateTexImageFailed(false),
+        mQueueItemLock(),
+        mQueueItemCondition(),
+        mQueueItems(),
+        mLastFrameNumberReceived(0),
+        mAutoRefresh(false),
+        mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
+        mQueuedFrames(0),
+        mSidebandStreamChanged(false) {
+    mCurrentState.requested_legacy = mCurrentState.active_legacy;
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for Layer
+// -----------------------------------------------------------------------
+
+void BufferQueueLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+    mConsumer->setReleaseFence(releaseFence);
+}
+
+void BufferQueueLayer::abandon() {
+    mConsumer->abandon();
+}
+
+void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
+    mConsumer->setTransformHint(orientation);
+}
+
+std::vector<OccupancyTracker::Segment> BufferQueueLayer::getOccupancyHistory(bool forceFlush) {
+    std::vector<OccupancyTracker::Segment> history;
+    status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
+    if (result != NO_ERROR) {
+        ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
+        return {};
+    }
+    return history;
+}
+
+bool BufferQueueLayer::getTransformToDisplayInverse() const {
+    return mConsumer->getTransformToDisplayInverse();
+}
+
+void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
+    if (!mConsumer->releasePendingBuffer()) {
+        return;
+    }
+
+    auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
+    mReleaseTimeline.updateSignalTimes();
+    mReleaseTimeline.push(releaseFenceTime);
+
+    Mutex::Autolock lock(mFrameEventHistoryMutex);
+    if (mPreviousFrameNumber != 0) {
+        mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
+                                      std::move(releaseFenceTime));
+    }
+}
+
+void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    mConsumer->setDefaultBufferSize(w, h);
+}
+
+int32_t BufferQueueLayer::getQueuedFrameCount() const {
+    return mQueuedFrames;
+}
+
+bool BufferQueueLayer::shouldPresentNow(const DispSync& dispSync) const {
+    if (getSidebandStreamChanged() || getAutoRefresh()) {
+        return true;
+    }
+
+    if (!hasDrawingBuffer()) {
+        return false;
+    }
+
+    Mutex::Autolock lock(mQueueItemLock);
+
+    const int64_t addedTime = mQueueItems[0].mTimestamp;
+    const nsecs_t expectedPresentTime = mConsumer->computeExpectedPresent(dispSync);
+
+    // Ignore timestamps more than a second in the future
+    const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1));
+    ALOGW_IF(!isPlausible,
+             "[%s] Timestamp %" PRId64 " seems implausible "
+             "relative to expectedPresent %" PRId64,
+             mName.string(), addedTime, expectedPresentTime);
+
+    const bool isDue = addedTime < expectedPresentTime;
+    return isDue || !isPlausible;
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for BufferLayer
+// -----------------------------------------------------------------------
+
+bool BufferQueueLayer::fenceHasSignaled() const {
+    if (latchUnsignaledBuffers()) {
+        return true;
+    }
+
+    if (!hasDrawingBuffer()) {
+        return true;
+    }
+
+    Mutex::Autolock lock(mQueueItemLock);
+    if (mQueueItems[0].mIsDroppable) {
+        // Even though this buffer's fence may not have signaled yet, it could
+        // be replaced by another buffer before it has a chance to, which means
+        // that it's possible to get into a situation where a buffer is never
+        // able to be latched. To avoid this, grab this buffer anyway.
+        return true;
+    }
+    return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+}
+
+nsecs_t BufferQueueLayer::getDesiredPresentTime() {
+    return mConsumer->getTimestamp();
+}
+
+std::shared_ptr<FenceTime> BufferQueueLayer::getCurrentFenceTime() const {
+    return mConsumer->getCurrentFenceTime();
+}
+
+void BufferQueueLayer::getDrawingTransformMatrix(float *matrix) {
+    return mConsumer->getTransformMatrix(matrix);
+}
+
+// NOTE: SurfaceFlinger's definitions of "Current" and "Drawing" do not neatly map to BufferQueue's
+// These functions get the fields for the frame that is currently in SurfaceFlinger's Drawing state
+// so the functions start with "getDrawing". The data is retrieved from the BufferQueueConsumer's
+// current buffer so the consumer functions start with "getCurrent".
+//
+// This results in the rather confusing functions below.
+uint32_t BufferQueueLayer::getDrawingTransform() const {
+    return mConsumer->getCurrentTransform();
+}
+
+ui::Dataspace BufferQueueLayer::getDrawingDataSpace() const {
+    return mConsumer->getCurrentDataSpace();
+}
+
+Rect BufferQueueLayer::getDrawingCrop() const {
+    return mConsumer->getCurrentCrop();
+}
+
+uint32_t BufferQueueLayer::getDrawingScalingMode() const {
+    return mConsumer->getCurrentScalingMode();
+}
+
+Region BufferQueueLayer::getDrawingSurfaceDamage() const {
+    return mConsumer->getSurfaceDamage();
+}
+
+const HdrMetadata& BufferQueueLayer::getDrawingHdrMetadata() const {
+    return mConsumer->getCurrentHdrMetadata();
+}
+
+int BufferQueueLayer::getDrawingApi() const {
+    return mConsumer->getCurrentApi();
+}
+
+PixelFormat BufferQueueLayer::getPixelFormat() const {
+    return mFormat;
+}
+
+uint64_t BufferQueueLayer::getFrameNumber() const {
+    Mutex::Autolock lock(mQueueItemLock);
+    return mQueueItems[0].mFrameNumber;
+}
+
+bool BufferQueueLayer::getAutoRefresh() const {
+    return mAutoRefresh;
+}
+
+bool BufferQueueLayer::getSidebandStreamChanged() const {
+    return mSidebandStreamChanged;
+}
+
+std::optional<Region> BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+    if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was true
+        // replicated in LayerBE until FE/BE is ready to be synchronized
+        getBE().compositionInfo.hwc.sidebandStream = mConsumer->getSidebandStream();
+        if (getBE().compositionInfo.hwc.sidebandStream != nullptr) {
+            setTransactionFlags(eTransactionNeeded);
+            mFlinger->setTransactionFlags(eTraversalNeeded);
+        }
+        recomputeVisibleRegions = true;
+
+        const State& s(getDrawingState());
+        return getTransform().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
+    }
+    return {};
+}
+
+bool BufferQueueLayer::hasDrawingBuffer() const {
+    return mQueuedFrames > 0;
+}
+
+void BufferQueueLayer::setFilteringEnabled(bool enabled) {
+    return mConsumer->setFilteringEnabled(enabled);
+}
+
+status_t BufferQueueLayer::bindTextureImage() const {
+    return mConsumer->bindTextureImage();
+}
+
+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
+    // buffer mode.
+    bool queuedBuffer = false;
+    LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
+                    getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+                    getTransformToDisplayInverse(), mFreezeGeometryUpdates);
+    status_t updateResult =
+            mConsumer->updateTexImage(&r, *mFlinger->mPrimaryDispSync, &mAutoRefresh, &queuedBuffer,
+                                      mLastFrameNumberReceived);
+    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.
+        mFlinger->signalLayerUpdate();
+        return BAD_VALUE;
+    } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
+        // If the buffer has been rejected, remove it from the shadow queue
+        // and return early
+        if (queuedBuffer) {
+            Mutex::Autolock lock(mQueueItemLock);
+            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+            mQueueItems.removeAt(0);
+            android_atomic_dec(&mQueuedFrames);
+        }
+        return BAD_VALUE;
+    } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) {
+        // This can occur if something goes wrong when trying to create the
+        // EGLImage for this buffer. If this happens, the buffer has already
+        // been released, so we need to clean up the queue and bug out
+        // early.
+        if (queuedBuffer) {
+            Mutex::Autolock lock(mQueueItemLock);
+            mQueueItems.clear();
+            android_atomic_and(0, &mQueuedFrames);
+            mTimeStats.clearLayerRecord(getName().c_str());
+        }
+
+        // Once we have hit this state, the shadow queue may no longer
+        // correctly reflect the incoming BufferQueue's contents, so even if
+        // updateTexImage starts working, the only safe course of action is
+        // to continue to ignore updates.
+        mUpdateTexImageFailed = true;
+
+        return BAD_VALUE;
+    }
+
+    if (queuedBuffer) {
+        // Autolock scope
+        auto currentFrameNumber = mConsumer->getFrameNumber();
+
+        Mutex::Autolock lock(mQueueItemLock);
+
+        // Remove any stale buffers that have been dropped during
+        // updateTexImage
+        while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
+            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+            mQueueItems.removeAt(0);
+            android_atomic_dec(&mQueuedFrames);
+        }
+
+        const std::string layerName(getName().c_str());
+        mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
+        mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
+
+        mQueueItems.removeAt(0);
+    }
+
+    // Decrement the queued-frames count.  Signal another event if we
+    // have more frames pending.
+    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
+        mFlinger->signalLayerUpdate();
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferQueueLayer::updateActiveBuffer() {
+    // update the active buffer
+    mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
+    getBE().compositionInfo.mBuffer = mActiveBuffer;
+    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+
+    if (mActiveBuffer == nullptr) {
+        // this can only happen if the very first buffer was rejected.
+        return BAD_VALUE;
+    }
+    return NO_ERROR;
+}
+
+status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) {
+    mPreviousFrameNumber = mCurrentFrameNumber;
+    mCurrentFrameNumber = mConsumer->getFrameNumber();
+
+    {
+        Mutex::Autolock lock(mFrameEventHistoryMutex);
+        mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+    }
+    return NO_ERROR;
+}
+
+void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+    const auto displayId = display->getId();
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
+    auto& hwcLayer = hwcInfo.layer;
+
+    uint32_t hwcSlot = 0;
+    sp<GraphicBuffer> hwcBuffer;
+    hwcInfo.bufferCache.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));
+    }
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for BufferLayerConsumer::ContentsChangedListener
+// -----------------------------------------------------------------------
+
+void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
+    // Add this buffer from our internal queue tracker
+    { // Autolock scope
+        Mutex::Autolock lock(mQueueItemLock);
+        // Reset the frame number tracker when we receive the first buffer after
+        // a frame number reset
+        if (item.mFrameNumber == 1) {
+            mLastFrameNumberReceived = 0;
+        }
+
+        // Ensure that callbacks are handled in order
+        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+            if (result != NO_ERROR) {
+                ALOGE("[%s] Timed out waiting on callback", mName.string());
+            }
+        }
+
+        mQueueItems.push_back(item);
+        android_atomic_inc(&mQueuedFrames);
+
+        // Wake up any pending callbacks
+        mLastFrameNumberReceived = item.mFrameNumber;
+        mQueueItemCondition.broadcast();
+    }
+
+    mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
+                                             item.mGraphicBuffer->getHeight(), item.mFrameNumber);
+    mFlinger->signalLayerUpdate();
+}
+
+void BufferQueueLayer::onFrameReplaced(const BufferItem& item) {
+    { // Autolock scope
+        Mutex::Autolock lock(mQueueItemLock);
+
+        // Ensure that callbacks are handled in order
+        while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
+            if (result != NO_ERROR) {
+                ALOGE("[%s] Timed out waiting on callback", mName.string());
+            }
+        }
+
+        if (!hasDrawingBuffer()) {
+            ALOGE("Can't replace a frame on an empty queue");
+            return;
+        }
+        mQueueItems.editItemAt(mQueueItems.size() - 1) = item;
+
+        // Wake up any pending callbacks
+        mLastFrameNumberReceived = item.mFrameNumber;
+        mQueueItemCondition.broadcast();
+    }
+}
+
+void BufferQueueLayer::onSidebandStreamChanged() {
+    if (android_atomic_release_cas(false, true, &mSidebandStreamChanged) == 0) {
+        // mSidebandStreamChanged was false
+        mFlinger->signalLayerUpdate();
+    }
+}
+
+// -----------------------------------------------------------------------
+
+void BufferQueueLayer::onFirstRef() {
+    BufferLayer::onFirstRef();
+
+    // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer, true);
+    mProducer = new MonitoredProducer(producer, mFlinger, this);
+    {
+        // Grab the SF state lock during this since it's the only safe way to access RenderEngine
+        Mutex::Autolock lock(mFlinger->mStateLock);
+        mConsumer =
+                new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
+    }
+    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+    mConsumer->setContentsChangedListener(this);
+    mConsumer->setName(mName);
+
+    if (mFlinger->isLayerTripleBufferingDisabled()) {
+        mProducer->setMaxDequeuedBufferCount(2);
+    }
+}
+
+status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
+    uint32_t const maxSurfaceDims =
+            min(mFlinger->getMaxTextureSize(), mFlinger->getMaxViewportDims());
+
+    // never allow a surface larger than what our underlying GL implementation
+    // can handle.
+    if ((uint32_t(w) > maxSurfaceDims) || (uint32_t(h) > maxSurfaceDims)) {
+        ALOGE("dimensions too large %u x %u", uint32_t(w), uint32_t(h));
+        return BAD_VALUE;
+    }
+
+    mFormat = format;
+
+    setDefaultBufferSize(w, h);
+    mConsumer->setDefaultBufferFormat(format);
+    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+
+    return NO_ERROR;
+}
+
+sp<IGraphicBufferProducer> BufferQueueLayer::getProducer() const {
+    return mProducer;
+}
+
+uint32_t BufferQueueLayer::getProducerStickyTransform() const {
+    int producerStickyTransform = 0;
+    int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform);
+    if (ret != OK) {
+        ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__,
+              strerror(-ret), ret);
+        return 0;
+    }
+    return static_cast<uint32_t>(producerStickyTransform);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
new file mode 100644
index 0000000..579ed81
--- /dev/null
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2018 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 "BufferLayer.h"
+
+#include <utils/String8.h>
+
+namespace android {
+
+/*
+ * A new BufferQueue and a new BufferLayerConsumer are created when the
+ * BufferLayer is first referenced.
+ *
+ * This also implements onFrameAvailable(), which notifies SurfaceFlinger
+ * that new data has arrived.
+ */
+class BufferQueueLayer : public BufferLayer, public BufferLayerConsumer::ContentsChangedListener {
+public:
+    BufferQueueLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+                     uint32_t w, uint32_t h, uint32_t flags);
+
+    // -----------------------------------------------------------------------
+    // Interface implementation for Layer
+    // -----------------------------------------------------------------------
+public:
+    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+
+    void abandon() override;
+
+    void setTransformHint(uint32_t orientation) const override;
+
+    std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
+
+    bool getTransformToDisplayInverse() const override;
+
+    // If a buffer was replaced this frame, release the former buffer
+    void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
+
+    void setDefaultBufferSize(uint32_t w, uint32_t h) override;
+
+    int32_t getQueuedFrameCount() const override;
+
+    bool shouldPresentNow(const DispSync& dispSync) const override;
+    // -----------------------------------------------------------------------
+
+    // -----------------------------------------------------------------------
+    // Interface implementation for BufferLayer
+    // -----------------------------------------------------------------------
+public:
+    bool fenceHasSignaled() const override;
+
+private:
+    nsecs_t getDesiredPresentTime() override;
+    std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
+
+    void getDrawingTransformMatrix(float *matrix) override;
+    uint32_t getDrawingTransform() const override;
+    ui::Dataspace getDrawingDataSpace() const override;
+    Rect getDrawingCrop() const override;
+    uint32_t getDrawingScalingMode() const override;
+    Region getDrawingSurfaceDamage() const override;
+    const HdrMetadata& getDrawingHdrMetadata() const override;
+    int getDrawingApi() const override;
+    PixelFormat getPixelFormat() const override;
+
+    uint64_t getFrameNumber() const override;
+
+    bool getAutoRefresh() const override;
+    bool getSidebandStreamChanged() const override;
+
+    std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+
+    bool hasDrawingBuffer() const override;
+
+    void setFilteringEnabled(bool enabled) override;
+
+    status_t bindTextureImage() const override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+
+    status_t updateActiveBuffer() override;
+    status_t updateFrameNumber(nsecs_t latchTime) override;
+
+    void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+    // -----------------------------------------------------------------------
+
+    // -----------------------------------------------------------------------
+    // Interface implementation for BufferLayerConsumer::ContentsChangedListener
+    // -----------------------------------------------------------------------
+protected:
+    void onFrameAvailable(const BufferItem& item) override;
+    void onFrameReplaced(const BufferItem& item) override;
+    void onSidebandStreamChanged() override;
+    // -----------------------------------------------------------------------
+
+public:
+    status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format);
+
+    sp<IGraphicBufferProducer> getProducer() const;
+
+private:
+    // Temporary - Used only for LEGACY camera mode.
+    uint32_t getProducerStickyTransform() const;
+
+    void onFirstRef() override;
+
+    sp<BufferLayerConsumer> mConsumer;
+    sp<IGraphicBufferProducer> mProducer;
+
+    PixelFormat mFormat;
+
+    // Only accessed on the main thread.
+    uint64_t mPreviousFrameNumber;
+    bool mUpdateTexImageFailed;
+
+    // Local copy of the queued contents of the incoming BufferQueue
+    mutable Mutex mQueueItemLock;
+    Condition mQueueItemCondition;
+    Vector<BufferItem> mQueueItems;
+    std::atomic<uint64_t> mLastFrameNumberReceived;
+
+    bool mAutoRefresh;
+    int mActiveBufferSlot;
+
+    // thread-safe
+    volatile int32_t mQueuedFrames;
+    volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
new file mode 100644
index 0000000..44fa760
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "BufferStateLayer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "BufferStateLayer.h"
+#include "RenderEngine/Image.h"
+#include "clz.h"
+
+#include <private/gui/SyncFeatures.h>
+
+namespace android {
+
+static const std::array<float, 16> IDENTITY_MATRIX{1, 0, 0, 0,
+                                                   0, 1, 0, 0,
+                                                   0, 0, 1, 0,
+                                                   0, 0, 0, 1};
+
+BufferStateLayer::BufferStateLayer(SurfaceFlinger* flinger, const sp<Client>& client,
+                                   const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+      : BufferLayer(flinger, client, name, w, h, flags),
+        mSidebandStreamChanged(false),
+        mFrameNumber(0) {
+    mTransformMatrix = IDENTITY_MATRIX;
+}
+
+// -----------------------------------------------------------------------
+// Interface implementation for Layer
+// -----------------------------------------------------------------------
+void BufferStateLayer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {
+    // TODO(marissaw): send the release fence back to buffer owner
+    return;
+}
+
+void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
+    // TODO(marissaw): send the transform hint to buffer owner
+    return;
+}
+
+void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
+    // TODO(marissaw): use this to signal the buffer owner
+    return;
+}
+
+bool BufferStateLayer::shouldPresentNow(const DispSync& /*dispSync*/) const {
+    if (getSidebandStreamChanged() || getAutoRefresh()) {
+        return true;
+    }
+
+    return hasDrawingBuffer();
+}
+
+bool BufferStateLayer::getTransformToDisplayInverse() const {
+    return mCurrentState.transformToDisplayInverse;
+}
+
+void BufferStateLayer::pushPendingState() {
+    if (!mCurrentState.modified) {
+        return;
+    }
+    mPendingStates.push_back(mCurrentState);
+    ATRACE_INT(mTransactionName.string(), mPendingStates.size());
+}
+
+bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
+    const bool stateUpdateAvailable = !mPendingStates.empty();
+    while (!mPendingStates.empty()) {
+        popPendingState(stateToCommit);
+    }
+    mCurrentState.modified = false;
+    return stateUpdateAvailable;
+}
+
+Rect BufferStateLayer::getCrop(const Layer::State& s) const {
+    return (getEffectiveScalingMode() == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+            ? GLConsumer::scaleDownCrop(s.crop, s.active.w, s.active.h)
+            : s.crop;
+}
+
+bool BufferStateLayer::setTransform(uint32_t transform) {
+    if (mCurrentState.transform == transform) return false;
+    mCurrentState.sequence++;
+    mCurrentState.transform = transform;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setTransformToDisplayInverse(bool transformToDisplayInverse) {
+    if (mCurrentState.transformToDisplayInverse == transformToDisplayInverse) return false;
+    mCurrentState.sequence++;
+    mCurrentState.transformToDisplayInverse = transformToDisplayInverse;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setCrop(const Rect& crop) {
+    if (mCurrentState.crop == crop) return false;
+    mCurrentState.sequence++;
+    mCurrentState.crop = crop;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setBuffer(sp<GraphicBuffer> buffer) {
+    mCurrentState.sequence++;
+    mCurrentState.buffer = buffer;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
+    mCurrentState.acquireFence = fence;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setDataspace(ui::Dataspace dataspace) {
+    if (mCurrentState.dataspace == dataspace) return false;
+    mCurrentState.sequence++;
+    mCurrentState.dataspace = dataspace;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setHdrMetadata(const HdrMetadata& hdrMetadata) {
+    if (mCurrentState.hdrMetadata == hdrMetadata) return false;
+    mCurrentState.sequence++;
+    mCurrentState.hdrMetadata = hdrMetadata;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setSurfaceDamageRegion(const Region& surfaceDamage) {
+    mCurrentState.sequence++;
+    mCurrentState.surfaceDamageRegion = surfaceDamage;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setApi(int32_t api) {
+    if (mCurrentState.api == api) return false;
+    mCurrentState.sequence++;
+    mCurrentState.api = api;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setSidebandStream(const sp<NativeHandle>& sidebandStream) {
+    if (mCurrentState.sidebandStream == sidebandStream) return false;
+    mCurrentState.sequence++;
+    mCurrentState.sidebandStream = sidebandStream;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+
+    if (!mSidebandStreamChanged.exchange(true)) {
+        // mSidebandStreamChanged was false
+        mFlinger->signalLayerUpdate();
+    }
+    return true;
+}
+
+bool BufferStateLayer::setSize(uint32_t w, uint32_t h) {
+    if (mCurrentState.active.w == w && mCurrentState.active.h == h) return false;
+    mCurrentState.active.w = w;
+    mCurrentState.active.h = h;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setPosition(float x, float y, bool /*immediate*/) {
+    if (mCurrentState.active.transform.tx() == x && mCurrentState.active.transform.ty() == y)
+        return false;
+
+    mCurrentState.active.transform.set(x, y);
+
+    mCurrentState.sequence++;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
+    mCurrentState.transparentRegionHint = transparent;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
+bool BufferStateLayer::setMatrix(const layer_state_t::matrix22_t& matrix,
+                                 bool allowNonRectPreservingTransforms) {
+    Transform t;
+    t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+
+    if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
+        ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
+        return false;
+    }
+
+    mCurrentState.sequence++;
+    mCurrentState.active.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+// -----------------------------------------------------------------------
+
+// -----------------------------------------------------------------------
+// Interface implementation for BufferLayer
+// -----------------------------------------------------------------------
+bool BufferStateLayer::fenceHasSignaled() const {
+    if (latchUnsignaledBuffers()) {
+        return true;
+    }
+
+    return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
+}
+
+nsecs_t BufferStateLayer::getDesiredPresentTime() {
+    // TODO(marissaw): support an equivalent to desiredPresentTime for timestats metrics
+    return 0;
+}
+
+std::shared_ptr<FenceTime> BufferStateLayer::getCurrentFenceTime() const {
+    return std::make_shared<FenceTime>(getDrawingState().acquireFence);
+}
+
+void BufferStateLayer::getDrawingTransformMatrix(float *matrix) {
+    std::copy(std::begin(mTransformMatrix), std::end(mTransformMatrix), matrix);
+}
+
+uint32_t BufferStateLayer::getDrawingTransform() const {
+    return getDrawingState().transform;
+}
+
+ui::Dataspace BufferStateLayer::getDrawingDataSpace() const {
+    return getDrawingState().dataspace;
+}
+
+Rect BufferStateLayer::getDrawingCrop() const {
+    return Rect::INVALID_RECT;
+}
+
+uint32_t BufferStateLayer::getDrawingScalingMode() const {
+    return NATIVE_WINDOW_SCALING_MODE_FREEZE;
+}
+
+Region BufferStateLayer::getDrawingSurfaceDamage() const {
+    return getDrawingState().surfaceDamageRegion;
+}
+
+const HdrMetadata& BufferStateLayer::getDrawingHdrMetadata() const {
+    return getDrawingState().hdrMetadata;
+}
+
+int BufferStateLayer::getDrawingApi() const {
+    return getDrawingState().api;
+}
+
+PixelFormat BufferStateLayer::getPixelFormat() const {
+    return mActiveBuffer->format;
+}
+
+uint64_t BufferStateLayer::getFrameNumber() const {
+    return mFrameNumber;
+}
+
+bool BufferStateLayer::getAutoRefresh() const {
+    // TODO(marissaw): support shared buffer mode
+    return false;
+}
+
+bool BufferStateLayer::getSidebandStreamChanged() const {
+    return mSidebandStreamChanged.load();
+}
+
+std::optional<Region> BufferStateLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+    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) {
+            setTransactionFlags(eTransactionNeeded);
+            mFlinger->setTransactionFlags(eTraversalNeeded);
+        }
+        recomputeVisibleRegions = true;
+
+        return getTransform().transform(Region(Rect(s.active.w, s.active.h)));
+    }
+    return {};
+}
+
+bool BufferStateLayer::hasDrawingBuffer() const {
+    return getDrawingState().buffer != nullptr;
+}
+
+void BufferStateLayer::setFilteringEnabled(bool enabled) {
+    GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mActiveBuffer, mCurrentCrop,
+                                       mCurrentTransform, enabled);
+}
+
+status_t BufferStateLayer::bindTextureImage() const {
+    const State& s(getDrawingState());
+    auto& engine(mFlinger->getRenderEngine());
+
+    if (!engine.isCurrent()) {
+        ALOGE("RenderEngine is not current");
+        return INVALID_OPERATION;
+    }
+
+    engine.checkErrors();
+
+    if (!mTextureImage) {
+        ALOGE("no currently-bound texture");
+        engine.bindExternalTextureImage(mTextureName, *engine.createImage());
+        return NO_INIT;
+    }
+
+    bool created =
+            mTextureImage->setNativeWindowBuffer(s.buffer->getNativeBuffer(),
+                                                 s.buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    if (!created) {
+        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+              s.buffer->getWidth(), s.buffer->getHeight(), s.buffer->getStride(),
+              s.buffer->getUsage(), s.buffer->getPixelFormat());
+        engine.bindExternalTextureImage(mTextureName, *engine.createImage());
+        return NO_INIT;
+    }
+
+    engine.bindExternalTextureImage(mTextureName, *mTextureImage);
+
+    // Wait for the new buffer to be ready.
+    if (s.acquireFence->isValid()) {
+        if (SyncFeatures::getInstance().useWaitSync()) {
+            base::unique_fd fenceFd(s.acquireFence->dup());
+            if (fenceFd == -1) {
+                ALOGE("error dup'ing fence fd: %d", errno);
+                return -errno;
+            }
+            if (!engine.waitFence(std::move(fenceFd))) {
+                ALOGE("failed to wait on fence fd");
+                return UNKNOWN_ERROR;
+            }
+        } else {
+            status_t err = s.acquireFence->waitForever("BufferStateLayer::bindTextureImage");
+            if (err != NO_ERROR) {
+                ALOGE("error waiting for fence: %d", err);
+                return err;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
+    const State& s(getDrawingState());
+
+    if (!s.buffer) {
+        return NO_ERROR;
+    }
+
+    auto& engine(mFlinger->getRenderEngine());
+    if (!engine.isCurrent()) {
+        ALOGE("RenderEngine is not current");
+        return INVALID_OPERATION;
+    }
+    engine.checkErrors();
+
+    // TODO(marissaw): once buffers are cached, don't create a new image everytime
+    mTextureImage = engine.createImage();
+
+    // Reject if the layer is invalid
+    uint32_t bufferWidth = s.buffer->width;
+    uint32_t bufferHeight = s.buffer->height;
+
+    if (s.transform & Transform::ROT_90) {
+        swap(bufferWidth, bufferHeight);
+    }
+
+    if (s.transformToDisplayInverse) {
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        if (invTransform & Transform::ROT_90) {
+            swap(bufferWidth, bufferHeight);
+        }
+    }
+
+    if (mOverrideScalingMode == NATIVE_WINDOW_SCALING_MODE_FREEZE &&
+        (s.active.w != bufferWidth || s.active.h != bufferHeight)) {
+        ALOGE("[%s] rejecting buffer: "
+              "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
+              mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
+        mTimeStats.removeTimeRecord(getName().c_str(), getFrameNumber());
+        return BAD_VALUE;
+    }
+
+    // Handle sync fences
+    if (SyncFeatures::getInstance().useNativeFenceSync()) {
+        base::unique_fd fenceFd = engine.flush();
+        if (fenceFd == -1) {
+            ALOGE("failed to flush RenderEngine");
+            mTimeStats.clearLayerRecord(getName().c_str());
+            return UNKNOWN_ERROR;
+        }
+
+        sp<Fence> fence(new Fence(std::move(fenceFd)));
+
+        // 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");
+            mTimeStats.clearLayerRecord(getName().c_str());
+            return BAD_VALUE;
+        }
+
+        auto incomingStatus = fence->getStatus();
+        if (incomingStatus == Fence::Status::Invalid) {
+            ALOGE("New fence has invalid state");
+            mDrawingState.acquireFence = fence;
+            mTimeStats.clearLayerRecord(getName().c_str());
+            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, fence);
+            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 = fence;
+                mTimeStats.clearLayerRecord(getName().c_str());
+                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 = fence;
+        }
+    } else {
+        // Bind the new buffer to the GL texture.
+        //
+        // Older devices require the "implicit" synchronization provided
+        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
+        // devices will either call this in Layer::onDraw, or (if it's not
+        // a GL-composited layer) not at all.
+        status_t err = bindTextureImage();
+        if (err != NO_ERROR) {
+            mTimeStats.clearLayerRecord(getName().c_str());
+            return BAD_VALUE;
+        }
+    }
+
+    // TODO(marissaw): properly support mTimeStats
+    const std::string layerName(getName().c_str());
+    mTimeStats.setPostTime(getName().c_str(), getFrameNumber(), latchTime);
+    mTimeStats.setAcquireFence(layerName, getFrameNumber(), getCurrentFenceTime());
+    mTimeStats.setLatchTime(layerName, getFrameNumber(), latchTime);
+
+    return NO_ERROR;
+}
+
+status_t BufferStateLayer::updateActiveBuffer() {
+    const State& s(getDrawingState());
+
+    if (s.buffer == nullptr) {
+        return BAD_VALUE;
+    }
+
+    mActiveBuffer = s.buffer;
+    getBE().compositionInfo.mBuffer = mActiveBuffer;
+    getBE().compositionInfo.mBufferSlot = 0;
+
+    return NO_ERROR;
+}
+
+status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
+    // TODO(marissaw): support frame history events
+    mCurrentFrameNumber = mFrameNumber;
+    return NO_ERROR;
+}
+
+void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+    const auto displayId = display->getId();
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
+    auto& hwcLayer = hwcInfo.layer;
+
+    const State& s(getDrawingState());
+
+    // TODO(marissaw): support more than one slot
+    uint32_t hwcSlot = 0;
+
+    auto error = hwcLayer->setBuffer(hwcSlot, s.buffer, s.acquireFence);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
+              s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+
+    mFrameNumber++;
+}
+
+void BufferStateLayer::onFirstRef() {
+    BufferLayer::onFirstRef();
+
+    if (const auto display = mFlinger->getDefaultDisplayDevice()) {
+        updateTransformHint(display);
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
new file mode 100644
index 0000000..4d7396e
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2018 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 "RenderEngine/Image.h"
+#include "RenderEngine/RenderEngine.h"
+
+#include "BufferLayer.h"
+#include "Layer.h"
+
+#include <gui/GLConsumer.h>
+#include <system/window.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class BufferStateLayer : public BufferLayer {
+public:
+    BufferStateLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
+                     uint32_t w, uint32_t h, uint32_t flags);
+
+    // -----------------------------------------------------------------------
+    // Interface implementation for Layer
+    // -----------------------------------------------------------------------
+    void onLayerDisplayed(const sp<Fence>& releaseFence) override;
+    void setTransformHint(uint32_t orientation) const override;
+    void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
+
+    bool shouldPresentNow(const DispSync& dispSync) const override;
+
+    bool getTransformToDisplayInverse() const override;
+
+    uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
+        return flags;
+    }
+    void pushPendingState() override;
+    bool applyPendingStates(Layer::State* stateToCommit) override;
+
+    uint32_t getActiveWidth(const Layer::State& s) const override { return s.active.w; }
+    uint32_t getActiveHeight(const Layer::State& s) const override { return s.active.h; }
+    Transform getActiveTransform(const Layer::State& s) const override {
+        return s.active.transform;
+    }
+    Region getActiveTransparentRegion(const Layer::State& s) const override {
+        return s.transparentRegionHint;
+    }
+    Rect getCrop(const Layer::State& s) const;
+    Rect getFinalCrop(const Layer::State& /*s*/) const { return Rect::EMPTY_RECT; }
+
+    bool setTransform(uint32_t transform) override;
+    bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
+    bool setCrop(const Rect& crop) override;
+    bool setBuffer(sp<GraphicBuffer> buffer) override;
+    bool setAcquireFence(const sp<Fence>& fence) override;
+    bool setDataspace(ui::Dataspace dataspace) override;
+    bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
+    bool setSurfaceDamageRegion(const Region& surfaceDamage) override;
+    bool setApi(int32_t api) override;
+    bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
+
+    bool setSize(uint32_t w, uint32_t h) override;
+    bool setPosition(float x, float y, bool immediate) override;
+    bool setTransparentRegionHint(const Region& transparent) override;
+    bool setMatrix(const layer_state_t::matrix22_t& matrix,
+                   bool allowNonRectPreservingTransforms) override;
+
+    // Override to ignore legacy layer state properties that are not used by BufferStateLayer
+    bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; };
+    bool setFinalCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; };
+    void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
+                                      uint64_t /*frameNumber*/) override {}
+    void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
+                                      uint64_t /*frameNumber*/) override {}
+    // -----------------------------------------------------------------------
+
+    // -----------------------------------------------------------------------
+    // Interface implementation for BufferLayer
+    // -----------------------------------------------------------------------
+    bool fenceHasSignaled() const override;
+
+private:
+    nsecs_t getDesiredPresentTime() override;
+    std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
+
+    void getDrawingTransformMatrix(float *matrix) override;
+    uint32_t getDrawingTransform() const override;
+    ui::Dataspace getDrawingDataSpace() const override;
+    Rect getDrawingCrop() const override;
+    uint32_t getDrawingScalingMode() const override;
+    Region getDrawingSurfaceDamage() const override;
+    const HdrMetadata& getDrawingHdrMetadata() const override;
+    int getDrawingApi() const override;
+    PixelFormat getPixelFormat() const override;
+
+    uint64_t getFrameNumber() const override;
+
+    bool getAutoRefresh() const override;
+    bool getSidebandStreamChanged() const override;
+
+    std::optional<Region> latchSidebandStream(bool& recomputeVisibleRegions) override;
+
+    bool hasDrawingBuffer() const override;
+
+    void setFilteringEnabled(bool enabled) override;
+
+    status_t bindTextureImage() const override;
+    status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+
+    status_t updateActiveBuffer() override;
+    status_t updateFrameNumber(nsecs_t latchTime) override;
+
+    void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+    // -----------------------------------------------------------------------
+private:
+    void onFirstRef() override;
+
+    std::unique_ptr<RE::Image> mTextureImage;
+
+    std::array<float, 16> mTransformMatrix;
+
+    std::atomic<bool> mSidebandStreamChanged;
+
+    uint32_t mFrameNumber;
+
+    // TODO(marissaw): support sticky transform for LEGACY camera mode
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 10075ae..bac46a3 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -43,7 +43,7 @@
 }
 
 void ColorLayer::onDraw(const RenderArea& renderArea, const Region& /* clip */,
-                        bool useIdentityTransform) const {
+                        bool useIdentityTransform) {
     half4 color = getColor();
     if (color.a > 0) {
         computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
@@ -54,7 +54,7 @@
     }
 }
 
-void ColorLayer::drawNow(const RenderArea& renderArea, bool useIdentityTransform) const {
+void ColorLayer::drawNow(const RenderArea& renderArea, bool useIdentityTransform) {
     CompositionInfo& compositionInfo = getBE().compositionInfo;
     auto& engine(mFlinger->getRenderEngine());
 
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 8417135..429ad79 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -31,8 +31,8 @@
 
     virtual const char* getTypeId() const { return "ColorLayer"; }
     virtual void onDraw(const RenderArea& renderArea, const Region& clip,
-                        bool useIdentityTransform) const;
-    void drawNow(const RenderArea& , bool ) const;
+                        bool useIdentityTransform);
+    void drawNow(const RenderArea&, bool);
     bool isVisible() const override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display) override;
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 320c0df..5ad5d56 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -28,9 +28,9 @@
     mDrawingState = mCurrentState;
 }
 
-void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) const {}
+void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) {}
 
-void ContainerLayer::drawNow(const RenderArea&, bool) const {}
+void ContainerLayer::drawNow(const RenderArea&, bool) {}
 
 bool ContainerLayer::isVisible() const {
     return !isHiddenByPolicy();
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 29a5c3a..051e765 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -31,8 +31,8 @@
 
     const char* getTypeId() const override { return "ContainerLayer"; }
     void onDraw(const RenderArea& renderArea, const Region& clip,
-                bool useIdentityTransform) const override;
-    void drawNow(const RenderArea& renderArea, bool useIdentityTransform) const override;
+                bool useIdentityTransform) override;
+    void drawNow(const RenderArea& renderArea, bool useIdentityTransform) override;
     bool isVisible() const override;
 
     void setPerFrameData(const sp<const DisplayDevice>& display) override;
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 829b53d..cdfbba3 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -40,6 +40,10 @@
 
 namespace android {
 
+DispSync::~DispSync() = default;
+
+namespace impl {
+
 // Setting this to true enables verbose tracing that can be used to debug
 // vsync event model or phase issues.
 static const bool kTraceDetailedInfo = false;
@@ -707,4 +711,6 @@
     result.appendFormat("current monotonic time: %" PRId64 "\n", now);
 }
 
+} // namespace impl
+
 } // namespace android
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index c00c161..1be131f 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -31,6 +31,36 @@
 
 class String8;
 class FenceTime;
+
+class DispSync {
+public:
+    class Callback {
+    public:
+        virtual ~Callback() = default;
+        virtual void onDispSyncEvent(nsecs_t when) = 0;
+    };
+
+    virtual ~DispSync();
+
+    virtual void reset() = 0;
+    virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0;
+    virtual void beginResync() = 0;
+    virtual bool addResyncSample(nsecs_t timestamp) = 0;
+    virtual void endResync() = 0;
+    virtual void setPeriod(nsecs_t period) = 0;
+    virtual nsecs_t getPeriod() = 0;
+    virtual void setRefreshSkipCount(int count) = 0;
+    virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) = 0;
+    virtual status_t removeEventListener(Callback* callback) = 0;
+    virtual status_t changePhaseOffset(Callback* callback, nsecs_t phase) = 0;
+    virtual nsecs_t computeNextRefresh(int periodOffset) const = 0;
+    virtual void setIgnorePresentFences(bool ignore) = 0;
+
+    virtual void dump(String8& result) const = 0;
+};
+
+namespace impl {
+
 class DispSyncThread;
 
 // DispSync maintains a model of the periodic hardware-based vsync events of a
@@ -46,21 +76,15 @@
 // current model accurately represents the hardware event times it will return
 // false to indicate that a resynchronization (via addResyncSample) is not
 // needed.
-class DispSync {
+class DispSync : public android::DispSync {
 public:
-    class Callback {
-    public:
-        virtual ~Callback(){};
-        virtual void onDispSyncEvent(nsecs_t when) = 0;
-    };
-
     explicit DispSync(const char* name);
-    ~DispSync();
+    ~DispSync() override;
 
     void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
 
     // reset clears the resync samples and error value.
-    void reset();
+    void reset() override;
 
     // addPresentFence adds a fence for use in validating the current vsync
     // event model.  The fence need not be signaled at the time
@@ -71,7 +95,7 @@
     //
     // This method should be called with the retire fence from each HWComposer
     // set call that affects the display.
-    bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
+    bool addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) override;
 
     // The beginResync, addResyncSample, and endResync methods are used to re-
     // synchronize the DispSync's model to the hardware vsync events.  The re-
@@ -84,45 +108,45 @@
     // is turned on (i.e. once immediately after it's turned on) and whenever
     // addPresentFence returns true indicating that the model has drifted away
     // from the hardware vsync events.
-    void beginResync();
-    bool addResyncSample(nsecs_t timestamp);
-    void endResync();
+    void beginResync() override;
+    bool addResyncSample(nsecs_t timestamp) override;
+    void endResync() override;
 
     // The setPeriod method sets the vsync event model's period to a specific
     // value.  This should be used to prime the model when a display is first
     // turned on.  It should NOT be used after that.
-    void setPeriod(nsecs_t period);
+    void setPeriod(nsecs_t period) override;
 
     // The getPeriod method returns the current vsync period.
-    nsecs_t getPeriod();
+    nsecs_t getPeriod() override;
 
     // setRefreshSkipCount specifies an additional number of refresh
     // cycles to skip.  For example, on a 60Hz display, a skip count of 1
     // will result in events happening at 30Hz.  Default is zero.  The idea
     // is to sacrifice smoothness for battery life.
-    void setRefreshSkipCount(int count);
+    void setRefreshSkipCount(int count) override;
 
     // addEventListener registers a callback to be called repeatedly at the
     // given phase offset from the hardware vsync events.  The callback is
     // called from a separate thread and it should return reasonably quickly
     // (i.e. within a few hundred microseconds).
-    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback);
+    status_t addEventListener(const char* name, nsecs_t phase, Callback* callback) override;
 
     // removeEventListener removes an already-registered event callback.  Once
     // this method returns that callback will no longer be called by the
     // DispSync object.
-    status_t removeEventListener(Callback* callback);
+    status_t removeEventListener(Callback* callback) override;
 
     // changePhaseOffset changes the phase offset of an already-registered event callback. The
     // method will make sure that there is no skipping or double-firing on the listener per frame,
     // even when changing the offsets multiple times.
-    status_t changePhaseOffset(Callback* callback, nsecs_t phase);
+    status_t changePhaseOffset(Callback* callback, nsecs_t phase) override;
 
     // computeNextRefresh computes when the next refresh is expected to begin.
     // The periodOffset value can be used to move forward or backward; an
     // offset of zero is the next refresh, -1 is the previous refresh, 1 is
     // the refresh after next. etc.
-    nsecs_t computeNextRefresh(int periodOffset) const;
+    nsecs_t computeNextRefresh(int periodOffset) const override;
 
     // In certain situations the present fences aren't a good indicator of vsync
     // time, e.g. when vr flinger is active, or simply aren't available,
@@ -130,10 +154,10 @@
     // whether or not DispSync ignores present fences. If present fences are
     // ignored, DispSync will always ask for hardware vsync events by returning
     // true from addPresentFence() and addResyncSample().
-    void setIgnorePresentFences(bool ignore);
+    void setIgnorePresentFences(bool ignore) override;
 
     // dump appends human-readable debug info to the result string.
-    void dump(String8& result) const;
+    void dump(String8& result) const override;
 
 private:
     void updateModelLocked();
@@ -206,6 +230,8 @@
     std::unique_ptr<Callback> mZeroPhaseTracer;
 };
 
+} // namespace impl
+
 } // namespace android
 
 #endif // ANDROID_DISPSYNC_H
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 40d89bd..ee9ee78 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -75,12 +75,8 @@
         mTransactionFlags(0),
         mPendingStateMutex(),
         mPendingStates(),
-        mQueuedFrames(0),
-        mSidebandStreamChanged(false),
-        mActiveBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
         mCurrentTransform(0),
         mOverrideScalingMode(-1),
-        mCurrentOpacity(true),
         mCurrentFrameNumber(0),
         mFrameLatencyNeeded(false),
         mFiltering(false),
@@ -88,11 +84,6 @@
         mProtectedByApp(false),
         mClientRef(client),
         mPotentialCursor(false),
-        mQueueItemLock(),
-        mQueueItemCondition(),
-        mQueueItems(),
-        mLastFrameNumberReceived(0),
-        mAutoRefresh(false),
         mFreezeGeometryUpdates(false),
         mCurrentChildren(LayerVector::StateSet::Current),
         mDrawingChildren(LayerVector::StateSet::Drawing),
@@ -108,21 +99,32 @@
     mName = name;
     mTransactionName = String8("TX - ") + mName;
 
-    mCurrentState.active.w = w;
-    mCurrentState.active.h = h;
+    mCurrentState.active_legacy.w = w;
+    mCurrentState.active_legacy.h = h;
     mCurrentState.flags = layerFlags;
-    mCurrentState.active.transform.set(0, 0);
-    mCurrentState.crop.makeInvalid();
-    mCurrentState.finalCrop.makeInvalid();
-    mCurrentState.requestedFinalCrop = mCurrentState.finalCrop;
-    mCurrentState.requestedCrop = mCurrentState.crop;
+    mCurrentState.active_legacy.transform.set(0, 0);
+    mCurrentState.crop_legacy.makeInvalid();
+    mCurrentState.finalCrop_legacy.makeInvalid();
+    mCurrentState.requestedFinalCrop_legacy = mCurrentState.finalCrop_legacy;
+    mCurrentState.requestedCrop_legacy = mCurrentState.crop_legacy;
     mCurrentState.z = 0;
     mCurrentState.color.a = 1.0f;
     mCurrentState.layerStack = 0;
     mCurrentState.sequence = 0;
-    mCurrentState.requested = mCurrentState.active;
+    mCurrentState.requested_legacy = mCurrentState.active_legacy;
     mCurrentState.appId = 0;
     mCurrentState.type = 0;
+    mCurrentState.active.w = 0;
+    mCurrentState.active.h = 0;
+    mCurrentState.active.transform.set(0, 0);
+    mCurrentState.transform = 0;
+    mCurrentState.transformToDisplayInverse = false;
+    mCurrentState.crop.makeInvalid();
+    mCurrentState.acquireFence = new Fence(-1);
+    mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
+    mCurrentState.hdrMetadata.validTypes = 0;
+    mCurrentState.surfaceDamageRegion.clear();
+    mCurrentState.api = -1;
 
     // drawing state & current state are identical
     mDrawingState = mCurrentState;
@@ -302,17 +304,19 @@
 
 Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
     const Layer::State& s(getDrawingState());
-    Rect win(s.active.w, s.active.h);
+    Rect win(getActiveWidth(s), getActiveHeight(s));
 
-    if (!s.crop.isEmpty()) {
-        win.intersect(s.crop, &win);
+    Rect crop = getCrop(s);
+    if (!crop.isEmpty()) {
+        win.intersect(crop, &win);
     }
 
     Transform t = getTransform();
     win = t.transform(win);
 
-    if (!s.finalCrop.isEmpty()) {
-        win.intersect(s.finalCrop, &win);
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        win.intersect(finalCrop, &win);
     }
 
     const sp<Layer>& p = mDrawingParent.promote();
@@ -331,7 +335,7 @@
     }
 
     if (reduceTransparentRegion) {
-        auto const screenTransparentRegion = t.transform(s.activeTransparentRegion);
+        auto const screenTransparentRegion = t.transform(getActiveTransparentRegion(s));
         win = reduce(win, screenTransparentRegion);
     }
 
@@ -340,15 +344,16 @@
 
 FloatRect Layer::computeBounds() const {
     const Layer::State& s(getDrawingState());
-    return computeBounds(s.activeTransparentRegion);
+    return computeBounds(getActiveTransparentRegion(s));
 }
 
 FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
     const Layer::State& s(getDrawingState());
-    Rect win(s.active.w, s.active.h);
+    Rect win(getActiveWidth(s), getActiveHeight(s));
 
-    if (!s.crop.isEmpty()) {
-        win.intersect(s.crop, &win);
+    Rect crop = getCrop(s);
+    if (!crop.isEmpty()) {
+        win.intersect(crop, &win);
     }
 
     const auto& p = mDrawingParent.promote();
@@ -360,15 +365,14 @@
         parentBounds = p->computeBounds(Region());
     }
 
-    Transform t = s.active.transform;
+    Transform t = s.active_legacy.transform;
 
-
-    if (p != nullptr || !s.finalCrop.isEmpty()) {
+    if (p != nullptr || !s.finalCrop_legacy.isEmpty()) {
         floatWin = t.transform(floatWin);
         floatWin = floatWin.intersect(parentBounds);
 
-        if (!s.finalCrop.isEmpty()) {
-            floatWin = floatWin.intersect(s.finalCrop.toFloatRect());
+        if (!s.finalCrop_legacy.isEmpty()) {
+            floatWin = floatWin.intersect(s.finalCrop_legacy.toFloatRect());
         }
         floatWin = t.inverse().transform(floatWin);
     }
@@ -389,9 +393,10 @@
     // FIXME: the 3 lines below can produce slightly incorrect clipping when we have
     // a viewport clipping and a window transform. we should use floating point to fix this.
 
-    Rect activeCrop(s.active.w, s.active.h);
-    if (!s.crop.isEmpty()) {
-        activeCrop.intersect(s.crop, &activeCrop);
+    Rect activeCrop(getActiveWidth(s), getActiveHeight(s));
+    Rect crop = getCrop(s);
+    if (!crop.isEmpty()) {
+        activeCrop.intersect(crop, &activeCrop);
     }
 
     Transform t = getTransform();
@@ -399,8 +404,9 @@
     if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
         activeCrop.clear();
     }
-    if (!s.finalCrop.isEmpty()) {
-        if (!activeCrop.intersect(s.finalCrop, &activeCrop)) {
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        if (!activeCrop.intersect(finalCrop, &activeCrop)) {
             activeCrop.clear();
         }
     }
@@ -434,12 +440,12 @@
     // transform.inverse().transform(transform.transform(Rect)) != Rect
     // in which case we need to make sure the final rect is clipped to the
     // display bounds.
-    if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+    if (!activeCrop.intersect(Rect(getActiveWidth(s), getActiveHeight(s)), &activeCrop)) {
         activeCrop.clear();
     }
 
     // subtract the transparent region and snap to the bounds
-    activeCrop = reduce(activeCrop, s.activeTransparentRegion);
+    activeCrop = reduce(activeCrop, getActiveTransparentRegion(s));
 
     // Transform the window crop to match the buffer coordinate system,
     // which means using the inverse of the current transform set on the
@@ -459,8 +465,8 @@
         invTransform = (Transform(invTransformOrient) * Transform(invTransform)).getOrientation();
     }
 
-    int winWidth = s.active.w;
-    int winHeight = s.active.h;
+    int winWidth = getActiveWidth(s);
+    int winHeight = getActiveHeight(s);
     if (invTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
         // If the activeCrop has been rotate the ends are rotated but not
         // the space itself so when transforming ends back we can't rely on
@@ -472,10 +478,10 @@
         if (is_h_flipped == is_v_flipped) {
             invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
         }
-        winWidth = s.active.h;
-        winHeight = s.active.w;
+        winWidth = getActiveHeight(s);
+        winHeight = getActiveWidth(s);
     }
-    const Rect winCrop = activeCrop.transform(invTransform, s.active.w, s.active.h);
+    const Rect winCrop = activeCrop.transform(invTransform, getActiveWidth(s), getActiveHeight(s));
 
     // below, crop is intersected with winCrop expressed in crop's coordinate space
     float xScale = crop.getWidth() / float(winWidth);
@@ -528,10 +534,10 @@
 
     // apply the layer's transform, followed by the display's global transform
     // here we're guaranteed that the layer's transform preserves rects
-    Region activeTransparentRegion(s.activeTransparentRegion);
+    Region activeTransparentRegion(getActiveTransparentRegion(s));
     Transform t = getTransform();
-    if (!s.crop.isEmpty()) {
-        Rect activeCrop(s.crop);
+    Rect activeCrop = getCrop(s);
+    if (!activeCrop.isEmpty()) {
         activeCrop = t.transform(activeCrop);
         if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
             activeCrop.clear();
@@ -543,22 +549,24 @@
         // transform.inverse().transform(transform.transform(Rect)) != Rect
         // in which case we need to make sure the final rect is clipped to the
         // display bounds.
-        if (!activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop)) {
+        if (!activeCrop.intersect(Rect(getActiveWidth(s), getActiveHeight(s)), &activeCrop)) {
             activeCrop.clear();
         }
         // mark regions outside the crop as transparent
-        activeTransparentRegion.orSelf(Rect(0, 0, s.active.w, activeCrop.top));
-        activeTransparentRegion.orSelf(Rect(0, activeCrop.bottom, s.active.w, s.active.h));
+        activeTransparentRegion.orSelf(Rect(0, 0, getActiveWidth(s), activeCrop.top));
+        activeTransparentRegion.orSelf(
+                Rect(0, activeCrop.bottom, getActiveWidth(s), getActiveHeight(s)));
         activeTransparentRegion.orSelf(Rect(0, activeCrop.top, activeCrop.left, activeCrop.bottom));
         activeTransparentRegion.orSelf(
-                Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom));
+                Rect(activeCrop.right, activeCrop.top, getActiveWidth(s), activeCrop.bottom));
     }
 
     // computeBounds returns a FloatRect to provide more accuracy during the
     // transformation. We then round upon constructing 'frame'.
     Rect frame{t.transform(computeBounds(activeTransparentRegion))};
-    if (!s.finalCrop.isEmpty()) {
-        if (!frame.intersect(s.finalCrop, &frame)) {
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        if (!frame.intersect(finalCrop, &frame)) {
             frame.clear();
         }
     }
@@ -691,16 +699,18 @@
 
     // Apply the layer's transform, followed by the display's global transform
     // Here we're guaranteed that the layer's transform preserves rects
-    Rect win(s.active.w, s.active.h);
-    if (!s.crop.isEmpty()) {
-        win.intersect(s.crop, &win);
+    Rect win(getActiveWidth(s), getActiveHeight(s));
+    Rect crop = getCrop(s);
+    if (!crop.isEmpty()) {
+        win.intersect(crop, &win);
     }
     // Subtract the transparent region and snap to the bounds
-    Rect bounds = reduce(win, s.activeTransparentRegion);
+    Rect bounds = reduce(win, getActiveTransparentRegion(s));
     Rect frame(getTransform().transform(bounds));
     frame.intersect(display->getViewport(), &frame);
-    if (!s.finalCrop.isEmpty()) {
-        frame.intersect(s.finalCrop, &frame);
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        frame.intersect(finalCrop, &frame);
     }
     auto& displayTransform = display->getTransform();
     auto position = displayTransform.transform(frame);
@@ -718,15 +728,15 @@
 // drawing...
 // ---------------------------------------------------------------------------
 
-void Layer::draw(const RenderArea& renderArea, const Region& clip) const {
+void Layer::draw(const RenderArea& renderArea, const Region& clip) {
     onDraw(renderArea, clip, false);
 }
 
-void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) const {
+void Layer::draw(const RenderArea& renderArea, bool useIdentityTransform) {
     onDraw(renderArea, Region(renderArea.getBounds()), useIdentityTransform);
 }
 
-void Layer::draw(const RenderArea& renderArea) const {
+void Layer::draw(const RenderArea& renderArea) {
     onDraw(renderArea, Region(renderArea.getBounds()), false);
 }
 
@@ -853,11 +863,12 @@
         rt = layerTransform.transform(rt);
     }
 
-    if (!s.finalCrop.isEmpty()) {
-        boundPoint(&lt, s.finalCrop);
-        boundPoint(&lb, s.finalCrop);
-        boundPoint(&rb, s.finalCrop);
-        boundPoint(&rt, s.finalCrop);
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        boundPoint(&lt, finalCrop);
+        boundPoint(&lb, finalCrop);
+        boundPoint(&rb, finalCrop);
+        boundPoint(&rt, finalCrop);
     }
 
     Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
@@ -907,22 +918,22 @@
 
     // If this transaction is waiting on the receipt of a frame, generate a sync
     // point and send it to the remote layer.
-    if (mCurrentState.barrierLayer != nullptr) {
-        sp<Layer> barrierLayer = mCurrentState.barrierLayer.promote();
+    if (mCurrentState.barrierLayer_legacy != nullptr) {
+        sp<Layer> barrierLayer = mCurrentState.barrierLayer_legacy.promote();
         if (barrierLayer == nullptr) {
             ALOGE("[%s] Unable to promote barrier Layer.", mName.string());
             // If we can't promote the layer we are intended to wait on,
             // then it is expired or otherwise invalid. Allow this transaction
             // to be applied as per normal (no synchronization).
-            mCurrentState.barrierLayer = nullptr;
+            mCurrentState.barrierLayer_legacy = nullptr;
         } else {
-            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber);
+            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy);
             if (barrierLayer->addSyncPoint(syncPoint)) {
                 mRemoteSyncPoints.push_back(std::move(syncPoint));
             } else {
                 // We already missed the frame we're supposed to synchronize
                 // on, so go ahead and apply the state update
-                mCurrentState.barrierLayer = nullptr;
+                mCurrentState.barrierLayer_legacy = nullptr;
             }
         }
 
@@ -944,7 +955,7 @@
 bool Layer::applyPendingStates(State* stateToCommit) {
     bool stateUpdateAvailable = false;
     while (!mPendingStates.empty()) {
-        if (mPendingStates[0].barrierLayer != nullptr) {
+        if (mPendingStates[0].barrierLayer_legacy != nullptr) {
             if (mRemoteSyncPoints.empty()) {
                 // If we don't have a sync point for this, apply it anyway. It
                 // will be visually wrong, but it should keep us from getting
@@ -955,7 +966,8 @@
                 continue;
             }
 
-            if (mRemoteSyncPoints.front()->getFrameNumber() != mPendingStates[0].frameNumber) {
+            if (mRemoteSyncPoints.front()->getFrameNumber() !=
+                mPendingStates[0].frameNumber_legacy) {
                 ALOGE("[%s] Unexpected sync point frame number found", mName.string());
 
                 // Signal our end of the sync point and then dispose of it
@@ -992,18 +1004,11 @@
     return stateUpdateAvailable;
 }
 
-uint32_t Layer::doTransaction(uint32_t flags) {
-    ATRACE_CALL();
-
-    pushPendingState();
-    Layer::State c = getCurrentState();
-    if (!applyPendingStates(&c)) {
-        return 0;
-    }
-
+uint32_t Layer::doTransactionResize(uint32_t flags, State* stateToCommit) {
     const Layer::State& s(getDrawingState());
 
-    const bool sizeChanged = (c.requested.w != s.requested.w) || (c.requested.h != s.requested.h);
+    const bool sizeChanged = (stateToCommit->requested_legacy.w != s.requested_legacy.w) ||
+            (stateToCommit->requested_legacy.h != s.requested_legacy.h);
 
     if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
@@ -1013,16 +1018,19 @@
                  "            requested={ wh={%4u,%4u} }}\n"
                  "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
                  "            requested={ wh={%4u,%4u} }}\n",
-                 this, getName().string(), mCurrentTransform,
-                 getEffectiveScalingMode(), c.active.w, c.active.h, c.crop.left, c.crop.top,
-                 c.crop.right, c.crop.bottom, c.crop.getWidth(), c.crop.getHeight(), c.requested.w,
-                 c.requested.h, s.active.w, s.active.h, s.crop.left, s.crop.top, s.crop.right,
-                 s.crop.bottom, s.crop.getWidth(), s.crop.getHeight(), s.requested.w,
-                 s.requested.h);
+                 this, getName().string(), mCurrentTransform, getEffectiveScalingMode(),
+                 stateToCommit->active_legacy.w, stateToCommit->active_legacy.h,
+                 stateToCommit->crop_legacy.left, stateToCommit->crop_legacy.top,
+                 stateToCommit->crop_legacy.right, stateToCommit->crop_legacy.bottom,
+                 stateToCommit->crop_legacy.getWidth(), stateToCommit->crop_legacy.getHeight(),
+                 stateToCommit->requested_legacy.w, stateToCommit->requested_legacy.h,
+                 s.active_legacy.w, s.active_legacy.h, s.crop_legacy.left, s.crop_legacy.top,
+                 s.crop_legacy.right, s.crop_legacy.bottom, s.crop_legacy.getWidth(),
+                 s.crop_legacy.getHeight(), s.requested_legacy.w, s.requested_legacy.h);
 
         // record the new size, form this point on, when the client request
         // a buffer, it'll get the new size.
-        setDefaultBufferSize(c.requested.w, c.requested.h);
+        setDefaultBufferSize(stateToCommit->requested_legacy.w, stateToCommit->requested_legacy.h);
     }
 
     // Don't let Layer::doTransaction update the drawing state
@@ -1043,7 +1051,9 @@
     // resizePending state is to avoid applying the state of the new buffer
     // to the old buffer. However in the state where we don't have an old buffer
     // there is no such concern but we may still be being used as a parent layer.
-    const bool resizePending = ((c.requested.w != c.active.w) || (c.requested.h != c.active.h)) &&
+    const bool resizePending =
+            ((stateToCommit->requested_legacy.w != stateToCommit->active_legacy.w) ||
+             (stateToCommit->requested_legacy.h != stateToCommit->active_legacy.h)) &&
             (getBE().compositionInfo.mBuffer != nullptr);
     if (!isFixedSize()) {
         if (resizePending && getBE().compositionInfo.hwc.sidebandStream == nullptr) {
@@ -1067,21 +1077,37 @@
         // being stored in the same data structure while having different latching rules.
         // b/38182305
         //
-        // Careful that "c" and editCurrentState may not begin as equivalent due to
+        // Careful that "stateToCommit" and editCurrentState may not begin as equivalent due to
         // applyPendingStates in the presence of deferred transactions.
         if (mFreezeGeometryUpdates) {
-            float tx = c.active.transform.tx();
-            float ty = c.active.transform.ty();
-            c.active = c.requested;
-            c.active.transform.set(tx, ty);
-            editCurrentState.active = c.active;
+            float tx = stateToCommit->active_legacy.transform.tx();
+            float ty = stateToCommit->active_legacy.transform.ty();
+            stateToCommit->active_legacy = stateToCommit->requested_legacy;
+            stateToCommit->active_legacy.transform.set(tx, ty);
+            editCurrentState.active_legacy = stateToCommit->active_legacy;
         } else {
-            editCurrentState.active = editCurrentState.requested;
-            c.active = c.requested;
+            editCurrentState.active_legacy = editCurrentState.requested_legacy;
+            stateToCommit->active_legacy = stateToCommit->requested_legacy;
         }
     }
 
-    if (s.active != c.active) {
+    return flags;
+}
+
+uint32_t Layer::doTransaction(uint32_t flags) {
+    ATRACE_CALL();
+
+    pushPendingState();
+    Layer::State c = getCurrentState();
+    if (!applyPendingStates(&c)) {
+        return 0;
+    }
+
+    flags = doTransactionResize(flags, &c);
+
+    const Layer::State& s(getDrawingState());
+
+    if (getActiveGeometry(c) != getActiveGeometry(s)) {
         // invalidate and recompute the visible regions if needed
         flags |= Layer::eVisibleRegion;
     }
@@ -1092,8 +1118,8 @@
         this->contentDirty = true;
 
         // we may use linear filtering, if the matrix scales us
-        const uint8_t type = c.active.transform.getType();
-        mNeedsFiltering = (!c.active.transform.preserveRects() || (type >= Transform::SCALE));
+        const uint8_t type = getActiveTransform(c).getType();
+        mNeedsFiltering = (!getActiveTransform(c).preserveRects() || (type >= Transform::SCALE));
     }
 
     // If the layer is hidden, signal and clear out all local sync points so
@@ -1121,20 +1147,21 @@
 }
 
 bool Layer::setPosition(float x, float y, bool immediate) {
-    if (mCurrentState.requested.transform.tx() == x && mCurrentState.requested.transform.ty() == y)
+    if (mCurrentState.requested_legacy.transform.tx() == x &&
+        mCurrentState.requested_legacy.transform.ty() == y)
         return false;
     mCurrentState.sequence++;
 
     // We update the requested and active position simultaneously because
     // we want to apply the position portion of the transform matrix immediately,
     // but still delay scaling when resizing a SCALING_MODE_FREEZE layer.
-    mCurrentState.requested.transform.set(x, y);
+    mCurrentState.requested_legacy.transform.set(x, y);
     if (immediate && !mFreezeGeometryUpdates) {
         // Here we directly update the active state
         // unlike other setters, because we store it within
         // the transform, but use different latching rules.
         // b/38182305
-        mCurrentState.active.transform.set(x, y);
+        mCurrentState.active_legacy.transform.set(x, y);
     }
     mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
 
@@ -1234,9 +1261,10 @@
 }
 
 bool Layer::setSize(uint32_t w, uint32_t h) {
-    if (mCurrentState.requested.w == w && mCurrentState.requested.h == h) return false;
-    mCurrentState.requested.w = w;
-    mCurrentState.requested.h = h;
+    if (mCurrentState.requested_legacy.w == w && mCurrentState.requested_legacy.h == h)
+        return false;
+    mCurrentState.requested_legacy.w = w;
+    mCurrentState.requested_legacy.h = h;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1274,13 +1302,15 @@
         return false;
     }
     mCurrentState.sequence++;
-    mCurrentState.requested.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
+    mCurrentState.requested_legacy.transform.set(matrix.dsdx, matrix.dtdy, matrix.dtdx,
+                                                 matrix.dsdy);
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
+
 bool Layer::setTransparentRegionHint(const Region& transparent) {
-    mCurrentState.requestedTransparentRegion = transparent;
+    mCurrentState.requestedTransparentRegion_legacy = transparent;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
     return true;
@@ -1295,12 +1325,12 @@
     return true;
 }
 
-bool Layer::setCrop(const Rect& crop, bool immediate) {
-    if (mCurrentState.requestedCrop == crop) return false;
+bool Layer::setCrop_legacy(const Rect& crop, bool immediate) {
+    if (mCurrentState.requestedCrop_legacy == crop) return false;
     mCurrentState.sequence++;
-    mCurrentState.requestedCrop = crop;
+    mCurrentState.requestedCrop_legacy = crop;
     if (immediate && !mFreezeGeometryUpdates) {
-        mCurrentState.crop = crop;
+        mCurrentState.crop_legacy = crop;
     }
     mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
 
@@ -1309,12 +1339,12 @@
     return true;
 }
 
-bool Layer::setFinalCrop(const Rect& crop, bool immediate) {
-    if (mCurrentState.requestedFinalCrop == crop) return false;
+bool Layer::setFinalCrop_legacy(const Rect& crop, bool immediate) {
+    if (mCurrentState.requestedFinalCrop_legacy == crop) return false;
     mCurrentState.sequence++;
-    mCurrentState.requestedFinalCrop = crop;
+    mCurrentState.requestedFinalCrop_legacy = crop;
     if (immediate && !mFreezeGeometryUpdates) {
-        mCurrentState.finalCrop = crop;
+        mCurrentState.finalCrop_legacy = crop;
     }
     mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
 
@@ -1354,24 +1384,23 @@
     return p->getLayerStack();
 }
 
-void Layer::deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
-    mCurrentState.barrierLayer = barrierLayer;
-    mCurrentState.frameNumber = frameNumber;
+void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
+    mCurrentState.barrierLayer_legacy = barrierLayer;
+    mCurrentState.frameNumber_legacy = frameNumber;
     // We don't set eTransactionNeeded, because just receiving a deferral
     // request without any other state updates shouldn't actually induce a delay
     mCurrentState.modified = true;
     pushPendingState();
-    mCurrentState.barrierLayer = nullptr;
-    mCurrentState.frameNumber = 0;
+    mCurrentState.barrierLayer_legacy = nullptr;
+    mCurrentState.frameNumber_legacy = 0;
     mCurrentState.modified = false;
 }
 
-void Layer::deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
+void Layer::deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle, uint64_t frameNumber) {
     sp<Handle> handle = static_cast<Handle*>(barrierHandle.get());
-    deferTransactionUntil(handle->owner.promote(), frameNumber);
+    deferTransactionUntil_legacy(handle->owner.promote(), frameNumber);
 }
 
-
 // ----------------------------------------------------------------------------
 // pageflip handling...
 // ----------------------------------------------------------------------------
@@ -1417,6 +1446,7 @@
 // debugging
 // ----------------------------------------------------------------------------
 
+// TODO(marissaw): add new layer state info to layer debugging
 LayerDebugInfo Layer::getLayerDebugInfo() const {
     LayerDebugInfo info;
     const Layer::State& ds = getDrawingState();
@@ -1424,25 +1454,25 @@
     sp<Layer> parent = getParent();
     info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
     info.mType = String8(getTypeId());
-    info.mTransparentRegion = ds.activeTransparentRegion;
+    info.mTransparentRegion = ds.activeTransparentRegion_legacy;
     info.mVisibleRegion = visibleRegion;
     info.mSurfaceDamageRegion = surfaceDamageRegion;
     info.mLayerStack = getLayerStack();
-    info.mX = ds.active.transform.tx();
-    info.mY = ds.active.transform.ty();
+    info.mX = ds.active_legacy.transform.tx();
+    info.mY = ds.active_legacy.transform.ty();
     info.mZ = ds.z;
-    info.mWidth = ds.active.w;
-    info.mHeight = ds.active.h;
-    info.mCrop = ds.crop;
-    info.mFinalCrop = ds.finalCrop;
+    info.mWidth = ds.active_legacy.w;
+    info.mHeight = ds.active_legacy.h;
+    info.mCrop = ds.crop_legacy;
+    info.mFinalCrop = ds.finalCrop_legacy;
     info.mColor = ds.color;
     info.mFlags = ds.flags;
     info.mPixelFormat = getPixelFormat();
     info.mDataSpace = static_cast<android_dataspace>(mCurrentDataSpace);
-    info.mMatrix[0][0] = ds.active.transform[0][0];
-    info.mMatrix[0][1] = ds.active.transform[0][1];
-    info.mMatrix[1][0] = ds.active.transform[1][0];
-    info.mMatrix[1][1] = ds.active.transform[1][1];
+    info.mMatrix[0][0] = ds.active_legacy.transform[0][0];
+    info.mMatrix[0][1] = ds.active_legacy.transform[0][1];
+    info.mMatrix[1][0] = ds.active_legacy.transform[1][0];
+    info.mMatrix[1][1] = ds.active_legacy.transform[1][1];
     {
         sp<const GraphicBuffer> buffer = mActiveBuffer;
         if (buffer != 0) {
@@ -1891,14 +1921,14 @@
                 bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth();
                 bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight();
             }
-            float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth);
-            float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight);
+            float sx = p->getActiveWidth(p->getDrawingState()) / static_cast<float>(bufferWidth);
+            float sy = p->getActiveHeight(p->getDrawingState()) / static_cast<float>(bufferHeight);
             Transform extraParentScaling;
             extraParentScaling.set(sx, 0, 0, sy);
             t = t * extraParentScaling;
         }
     }
-    return t * getDrawingState().active.transform;
+    return t * getActiveTransform(getDrawingState());
 }
 
 half Layer::getAlpha() const {
@@ -1927,7 +1957,7 @@
     const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
     const State& state = useDrawing ? mDrawingState : mCurrentState;
 
-    Transform requestedTransform = state.active.transform;
+    Transform requestedTransform = state.active_legacy.transform;
     Transform transform = getTransform();
 
     layerInfo->set_id(sequence);
@@ -1945,7 +1975,7 @@
         }
     }
 
-    LayerProtoHelper::writeToProto(state.activeTransparentRegion,
+    LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
                                    layerInfo->mutable_transparent_region());
     LayerProtoHelper::writeToProto(visibleRegion, layerInfo->mutable_visible_region());
     LayerProtoHelper::writeToProto(surfaceDamageRegion, layerInfo->mutable_damage_region());
@@ -1962,11 +1992,11 @@
     requestedPosition->set_y(requestedTransform.ty());
 
     SizeProto* size = layerInfo->mutable_size();
-    size->set_w(state.active.w);
-    size->set_h(state.active.h);
+    size->set_w(state.active_legacy.w);
+    size->set_h(state.active_legacy.h);
 
-    LayerProtoHelper::writeToProto(state.crop, layerInfo->mutable_crop());
-    LayerProtoHelper::writeToProto(state.finalCrop, layerInfo->mutable_final_crop());
+    LayerProtoHelper::writeToProto(state.crop_legacy, layerInfo->mutable_crop());
+    LayerProtoHelper::writeToProto(state.finalCrop_legacy, layerInfo->mutable_final_crop());
 
     layerInfo->set_is_opaque(isOpaque(state));
     layerInfo->set_invalidate(contentDirty);
@@ -2007,11 +2037,11 @@
     layerInfo->set_curr_frame(mCurrentFrameNumber);
 
     for (const auto& pendingState : mPendingStates) {
-        auto barrierLayer = pendingState.barrierLayer.promote();
+        auto barrierLayer = pendingState.barrierLayer_legacy.promote();
         if (barrierLayer != nullptr) {
             BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
             barrierLayerProto->set_id(barrierLayer->sequence);
-            barrierLayerProto->set_frame_number(pendingState.frameNumber);
+            barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
         }
     }
 }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index f724096..a48cdff 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -111,8 +111,8 @@
     };
 
     struct State {
-        Geometry active;
-        Geometry requested;
+        Geometry active_legacy;
+        Geometry requested_legacy;
         int32_t z;
 
         // The identifier of the layer stack this layer belongs to. A layer can
@@ -128,23 +128,23 @@
         bool modified;
 
         // Crop is expressed in layer space coordinate.
-        Rect crop;
-        Rect requestedCrop;
+        Rect crop_legacy;
+        Rect requestedCrop_legacy;
 
         // finalCrop is expressed in display space coordinate.
-        Rect finalCrop;
-        Rect requestedFinalCrop;
+        Rect finalCrop_legacy;
+        Rect requestedFinalCrop_legacy;
 
         // If set, defers this state update until the identified Layer
         // receives a frame with the given frameNumber
-        wp<Layer> barrierLayer;
-        uint64_t frameNumber;
+        wp<Layer> barrierLayer_legacy;
+        uint64_t frameNumber_legacy;
 
         // the transparentRegion hint is a bit special, it's latched only
         // when we receive a buffer -- this is because it's "content"
         // dependent.
-        Region activeTransparentRegion;
-        Region requestedTransparentRegion;
+        Region activeTransparentRegion_legacy;
+        Region requestedTransparentRegion_legacy;
 
         int32_t appId;
         int32_t type;
@@ -156,6 +156,24 @@
         SortedVector<wp<Layer>> zOrderRelatives;
 
         half4 color;
+
+        // The fields below this point are only used by BufferStateLayer
+        Geometry active;
+
+        uint32_t transform;
+        bool transformToDisplayInverse;
+
+        Rect crop;
+        Region transparentRegionHint;
+
+        sp<GraphicBuffer> buffer;
+        sp<Fence> acquireFence;
+        ui::Dataspace dataspace;
+        HdrMetadata hdrMetadata;
+        Region surfaceDamageRegion;
+        int32_t api;
+
+        sp<NativeHandle> sidebandStream;
     };
 
     Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
@@ -191,11 +209,12 @@
     // also the rendered size of the layer prior to any transformations. Parent
     // or local matrix transformations will not affect the size of the buffer,
     // but may affect it's on-screen size or clipping.
-    bool setSize(uint32_t w, uint32_t h);
+    virtual bool setSize(uint32_t w, uint32_t h);
     // Set a 2x2 transformation matrix on the layer. This transform
     // will be applied after parent transforms, but before any final
     // producer specified transform.
-    bool setMatrix(const layer_state_t::matrix22_t& matrix, bool allowNonRectPreservingTransforms);
+    virtual bool setMatrix(const layer_state_t::matrix22_t& matrix,
+                           bool allowNonRectPreservingTransforms);
 
     // This second set of geometry attributes are controlled by
     // setGeometryAppliesWithResize, and their default mode is to be
@@ -205,32 +224,45 @@
 
     // setPosition operates in parent buffer space (pre parent-transform) or display
     // space for top-level layers.
-    bool setPosition(float x, float y, bool immediate);
+    virtual bool setPosition(float x, float y, bool immediate);
     // Buffer space
-    bool setCrop(const Rect& crop, bool immediate);
+    virtual bool setCrop_legacy(const Rect& crop, bool immediate);
     // Parent buffer space/display space
-    bool setFinalCrop(const Rect& crop, bool immediate);
+    virtual bool setFinalCrop_legacy(const Rect& crop, bool immediate);
 
     // TODO(b/38182121): Could we eliminate the various latching modes by
     // using the layer hierarchy?
     // -----------------------------------------------------------------------
-    bool setLayer(int32_t z);
-    bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
+    virtual bool setLayer(int32_t z);
+    virtual bool setRelativeLayer(const sp<IBinder>& relativeToHandle, int32_t relativeZ);
 
-    bool setAlpha(float alpha);
-    bool setColor(const half3& color);
-    bool setTransparentRegionHint(const Region& transparent);
-    bool setFlags(uint8_t flags, uint8_t mask);
-    bool setLayerStack(uint32_t layerStack);
-    uint32_t getLayerStack() const;
-    void deferTransactionUntil(const sp<IBinder>& barrierHandle, uint64_t frameNumber);
-    void deferTransactionUntil(const sp<Layer>& barrierLayer, uint64_t frameNumber);
-    bool setOverrideScalingMode(int32_t overrideScalingMode);
-    void setInfo(int32_t type, int32_t appId);
-    bool reparentChildren(const sp<IBinder>& layer);
-    void setChildrenDrawingParent(const sp<Layer>& layer);
-    bool reparent(const sp<IBinder>& newParentHandle);
-    bool detachChildren();
+    virtual bool setAlpha(float alpha);
+    virtual bool setColor(const half3& color);
+    virtual bool setTransparentRegionHint(const Region& transparent);
+    virtual bool setFlags(uint8_t flags, uint8_t mask);
+    virtual bool setLayerStack(uint32_t layerStack);
+    virtual uint32_t getLayerStack() const;
+    virtual void deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle,
+                                              uint64_t frameNumber);
+    virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
+    virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
+    virtual void setInfo(int32_t type, int32_t appId);
+    virtual bool reparentChildren(const sp<IBinder>& layer);
+    virtual void setChildrenDrawingParent(const sp<Layer>& layer);
+    virtual bool reparent(const sp<IBinder>& newParentHandle);
+    virtual bool detachChildren();
+
+    // Used only to set BufferStateLayer state
+    virtual bool setTransform(uint32_t /*transform*/) { return false; };
+    virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
+    virtual bool setCrop(const Rect& /*crop*/) { return false; };
+    virtual bool setBuffer(sp<GraphicBuffer> /*buffer*/) { return false; };
+    virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
+    virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; };
+    virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; };
+    virtual bool setSurfaceDamageRegion(const Region& /*surfaceDamage*/) { return false; };
+    virtual bool setApi(int32_t /*api*/) { return false; };
+    virtual bool setSidebandStream(const sp<NativeHandle>& /*sidebandStream*/) { return false; };
 
     ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
 
@@ -310,12 +342,24 @@
 
     void writeToProto(LayerProto* layerInfo, int32_t displayId);
 
+    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; }
+    virtual uint32_t getActiveHeight(const Layer::State& s) const { return s.active_legacy.h; }
+    virtual Transform getActiveTransform(const Layer::State& s) const {
+        return s.active_legacy.transform;
+    }
+    virtual Region getActiveTransparentRegion(const Layer::State& s) const {
+        return s.activeTransparentRegion_legacy;
+    }
+    virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
+    virtual Rect getFinalCrop(const Layer::State& s) const { return s.finalCrop_legacy; }
+
 protected:
     /*
      * onDraw - draws the surface.
      */
     virtual void onDraw(const RenderArea& renderArea, const Region& clip,
-                        bool useIdentityTransform) const = 0;
+                        bool useIdentityTransform) = 0;
 
 public:
     virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
@@ -369,9 +413,9 @@
      * draw - performs some global clipping optimizations
      * and calls onDraw().
      */
-    void draw(const RenderArea& renderArea, const Region& clip) const;
-    void draw(const RenderArea& renderArea, bool useIdentityTransform) const;
-    void draw(const RenderArea& renderArea) const;
+    void draw(const RenderArea& renderArea, const Region& clip);
+    void draw(const RenderArea& renderArea, bool useIdentityTransform);
+    void draw(const RenderArea& renderArea);
 
     /*
      * drawNow uses the renderEngine to draw the layer.  This is different than the
@@ -381,7 +425,7 @@
      * is used for screen captures which happens separately from the frame
      * compositing path.
      */
-    virtual void drawNow(const RenderArea& renderArea, bool useIdentityTransform) const = 0;
+    virtual void drawNow(const RenderArea& renderArea, bool useIdentityTransform) = 0;
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
@@ -425,7 +469,6 @@
 
     virtual bool isBufferLatched() const { return false; }
 
-    bool isPotentialCursor() const { return mPotentialCursor; }
     /*
      * called with the state lock from a binder thread when the layer is
      * removed from the current list to the pending removal list
@@ -449,13 +492,11 @@
     Rect getContentCrop() const;
 
     /*
-     * Returns if a frame is queued.
+     * Returns if a frame is ready
      */
-    bool hasQueuedFrame() const {
-        return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
-    }
+    virtual bool hasReadyFrame() const { return false; }
 
-    int32_t getQueuedFrameCount() const { return mQueuedFrames; }
+    virtual int32_t getQueuedFrameCount() const { return 0; }
 
     // -----------------------------------------------------------------------
 
@@ -539,7 +580,7 @@
     // SurfaceFlinger to complete a transaction.
     void commitChildList();
     int32_t getZ() const;
-    void pushPendingState();
+    virtual void pushPendingState();
 
 protected:
     // constant
@@ -623,7 +664,8 @@
     bool addSyncPoint(const std::shared_ptr<SyncPoint>& point);
 
     void popPendingState(State* stateToCommit);
-    bool applyPendingStates(State* stateToCommit);
+    virtual bool applyPendingStates(State* stateToCommit);
+    virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
 
     void clearSyncPoints();
 
@@ -674,10 +716,6 @@
     Mutex mPendingStateMutex;
     Vector<State> mPendingStates;
 
-    // thread-safe
-    volatile int32_t mQueuedFrames;
-    volatile int32_t mSidebandStreamChanged; // used like an atomic boolean
-
     // Timestamp history for UIAutomation. Thread safe.
     FrameTracker mFrameTracker;
 
@@ -691,15 +729,12 @@
     TimeStats& mTimeStats = TimeStats::getInstance();
 
     // main thread
-    int mActiveBufferSlot;
     sp<GraphicBuffer> mActiveBuffer;
-    sp<NativeHandle> mSidebandStream;
     ui::Dataspace mCurrentDataSpace = ui::Dataspace::UNKNOWN;
     Rect mCurrentCrop;
     uint32_t mCurrentTransform;
     // We encode unset as -1.
     int32_t mOverrideScalingMode;
-    bool mCurrentOpacity;
     std::atomic<uint64_t> mCurrentFrameNumber;
     bool mFrameLatencyNeeded;
     // Whether filtering is forced on or not
@@ -720,12 +755,6 @@
     // This layer can be a cursor on some displays.
     bool mPotentialCursor;
 
-    // Local copy of the queued contents of the incoming BufferQueue
-    mutable Mutex mQueueItemLock;
-    Condition mQueueItemCondition;
-    Vector<BufferItem> mQueueItems;
-    std::atomic<uint64_t> mLastFrameNumberReceived;
-    bool mAutoRefresh;
     bool mFreezeGeometryUpdates;
 
     // Child list about to be committed/used for editing.
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 9aa43f7..b5aceba 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -77,6 +77,8 @@
 public:
     friend class Layer;
     friend class BufferLayer;
+    friend class BufferQueueLayer;
+    friend class BufferStateLayer;
     friend class ColorLayer;
     friend class SurfaceFlinger;
 
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 381ea4a..70558d4 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -65,20 +65,21 @@
 
     int actualScalingMode = mOverrideScalingMode >= 0 ? mOverrideScalingMode : item.mScalingMode;
     bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
-    if (mFront.active != mFront.requested) {
-        if (isFixedSize || (bufWidth == mFront.requested.w && bufHeight == mFront.requested.h)) {
+    if (mFront.active_legacy != mFront.requested_legacy) {
+        if (isFixedSize ||
+            (bufWidth == mFront.requested_legacy.w && bufHeight == mFront.requested_legacy.h)) {
             // Here we pretend the transaction happened by updating the
             // current and drawing states. Drawing state is only accessed
             // in this thread, no need to have it locked
-            mFront.active = mFront.requested;
+            mFront.active_legacy = mFront.requested_legacy;
 
             // We also need to update the current state so that
             // we don't end-up overwriting the drawing state with
             // this stale current state during the next transaction
             //
             // NOTE: We don't need to hold the transaction lock here
-            // because State::active is only accessed from this thread.
-            mCurrent.active = mFront.active;
+            // because State::active_legacy is only accessed from this thread.
+            mCurrent.active_legacy = mFront.active_legacy;
             mCurrent.modified = true;
 
             // recompute visible region
@@ -86,35 +87,37 @@
 
             mFreezeGeometryUpdates = false;
 
-            if (mFront.crop != mFront.requestedCrop) {
-                mFront.crop = mFront.requestedCrop;
-                mCurrent.crop = mFront.requestedCrop;
+            if (mFront.crop_legacy != mFront.requestedCrop_legacy) {
+                mFront.crop_legacy = mFront.requestedCrop_legacy;
+                mCurrent.crop_legacy = mFront.requestedCrop_legacy;
                 mRecomputeVisibleRegions = true;
             }
-            if (mFront.finalCrop != mFront.requestedFinalCrop) {
-                mFront.finalCrop = mFront.requestedFinalCrop;
-                mCurrent.finalCrop = mFront.requestedFinalCrop;
+            if (mFront.finalCrop_legacy != mFront.requestedFinalCrop_legacy) {
+                mFront.finalCrop_legacy = mFront.requestedFinalCrop_legacy;
+                mCurrent.finalCrop_legacy = mFront.requestedFinalCrop_legacy;
                 mRecomputeVisibleRegions = true;
             }
         }
 
         ALOGD_IF(DEBUG_RESIZE,
                  "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n"
-                 "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) "
+                 "  drawing={ active_legacy   ={ wh={%4u,%4u} crop_legacy={%4d,%4d,%4d,%4d} "
+                 "(%4d,%4d) "
                  "}\n"
-                 "            requested={ wh={%4u,%4u} }}\n",
-                 mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode, mFront.active.w,
-                 mFront.active.h, mFront.crop.left, mFront.crop.top, mFront.crop.right,
-                 mFront.crop.bottom, mFront.crop.getWidth(), mFront.crop.getHeight(),
-                 mFront.requested.w, mFront.requested.h);
+                 "            requested_legacy={ wh={%4u,%4u} }}\n",
+                 mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
+                 mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop_legacy.left,
+                 mFront.crop_legacy.top, mFront.crop_legacy.right, mFront.crop_legacy.bottom,
+                 mFront.crop_legacy.getWidth(), mFront.crop_legacy.getHeight(),
+                 mFront.requested_legacy.w, mFront.requested_legacy.h);
     }
 
     if (!isFixedSize && !mStickyTransformSet) {
-        if (mFront.active.w != bufWidth || mFront.active.h != bufHeight) {
+        if (mFront.active_legacy.w != bufWidth || mFront.active_legacy.h != bufHeight) {
             // reject this buffer
             ALOGE("[%s] rejecting buffer: "
-                  "bufWidth=%d, bufHeight=%d, front.active.{w=%d, h=%d}",
-                  mName, bufWidth, bufHeight, mFront.active.w, mFront.active.h);
+                  "bufWidth=%d, bufHeight=%d, front.active_legacy.{w=%d, h=%d}",
+                  mName, bufWidth, bufHeight, mFront.active_legacy.w, mFront.active_legacy.h);
             return true;
         }
     }
@@ -127,16 +130,17 @@
     // We latch the transparent region here, instead of above where we latch
     // the rest of the geometry because it is only content but not necessarily
     // resize dependent.
-    if (!mFront.activeTransparentRegion.isTriviallyEqual(mFront.requestedTransparentRegion)) {
-        mFront.activeTransparentRegion = mFront.requestedTransparentRegion;
+    if (!mFront.activeTransparentRegion_legacy.isTriviallyEqual(
+                mFront.requestedTransparentRegion_legacy)) {
+        mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy;
 
         // We also need to update the current state so that
         // we don't end-up overwriting the drawing state with
         // this stale current state during the next transaction
         //
         // NOTE: We don't need to hold the transaction lock here
-        // because State::active is only accessed from this thread.
-        mCurrent.activeTransparentRegion = mFront.activeTransparentRegion;
+        // because State::active_legacy is only accessed from this thread.
+        mCurrent.activeTransparentRegion_legacy = mFront.activeTransparentRegion_legacy;
 
         // recompute visible region
         mRecomputeVisibleRegions = true;
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 0b8b838..39f7e30 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -29,6 +29,7 @@
 
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
+#include <private/gui/SyncFeatures.h>
 
 using namespace android::hardware::configstore;
 using namespace android::hardware::configstore::V1_0;
@@ -175,6 +176,14 @@
     return mEGLConfig;
 }
 
+bool RenderEngine::useNativeFenceSync() const {
+    return SyncFeatures::getInstance().useNativeFenceSync();
+}
+
+bool RenderEngine::useWaitSync() const {
+    return SyncFeatures::getInstance().useWaitSync();
+}
+
 bool RenderEngine::isCurrent() const {
     return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
 }
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 95b9ec8..40bc966 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -69,6 +69,9 @@
     // dump the extension strings. always call the base class.
     virtual void dump(String8& result) = 0;
 
+    virtual bool useNativeFenceSync() const = 0;
+    virtual bool useWaitSync() const = 0;
+
     virtual bool isCurrent() const = 0;
     virtual bool setCurrentSurface(const RE::Surface& surface) = 0;
     virtual void resetCurrentSurface() = 0;
@@ -190,6 +193,9 @@
     // dump the extension strings. always call the base class.
     void dump(String8& result) override;
 
+    bool useNativeFenceSync() const override;
+    bool useWaitSync() const override;
+
     bool isCurrent() const;
     bool setCurrentSurface(const RE::Surface& surface) override;
     void resetCurrentSurface() override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ba5154d..31e4444 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -63,6 +63,8 @@
 #include <private/gui/SyncFeatures.h>
 
 #include "BufferLayer.h"
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
 #include "Client.h"
 #include "ColorLayer.h"
 #include "Colorizer.h"
@@ -262,7 +264,6 @@
         mDebugInTransaction(0),
         mLastTransactionTime(0),
         mForceFullDamage(false),
-        mPrimaryDispSync("PrimaryDispSync"),
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
         mHasPoweredOff(false),
@@ -323,7 +324,13 @@
     }
     ALOGV("Primary Display Orientation is set to %2d.", mPrimaryDisplayOrientation);
 
-    mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
+    // Note: We create a local temporary with the real DispSync implementation
+    // type temporarily so we can initialize it with the configured values,
+    // before storing it for more generic use using the interface type.
+    auto primaryDispSync = std::make_unique<impl::DispSync>("PrimaryDispSync");
+    primaryDispSync->init(SurfaceFlinger::hasSyncFramework,
+                          SurfaceFlinger::dispSyncPresentTimeOffset);
+    mPrimaryDispSync = std::move(primaryDispSync);
 
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
@@ -701,14 +708,14 @@
 
     // start the EventThread
     mEventThreadSource =
-            std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
-                                             true, "app");
+            std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
+                                             SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
     mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
                                                        [this] { resyncWithRateLimit(); },
                                                        impl::EventThread::InterceptVSyncsCallback(),
                                                        "appEventThread");
     mSfEventThreadSource =
-            std::make_unique<DispSyncSource>(&mPrimaryDispSync,
+            std::make_unique<DispSyncSource>(mPrimaryDispSync.get(),
                                              SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
 
     mSFEventThread =
@@ -994,8 +1001,8 @@
 
     // FIXME for now we always return stats for the primary display
     memset(stats, 0, sizeof(*stats));
-    stats->vsyncTime   = mPrimaryDispSync.computeNextRefresh(0);
-    stats->vsyncPeriod = mPrimaryDispSync.getPeriod();
+    stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0);
+    stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
     return NO_ERROR;
 }
 
@@ -1293,7 +1300,7 @@
 void SurfaceFlinger::enableHardwareVsync() {
     Mutex::Autolock _l(mHWVsyncLock);
     if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
-        mPrimaryDispSync.beginResync();
+        mPrimaryDispSync->beginResync();
         mEventControlThread->setVsyncEnabled(true);
         mPrimaryHWVsyncEnabled = true;
     }
@@ -1318,11 +1325,11 @@
     const auto activeConfig = getHwComposer().getActiveConfig(displayId);
     const nsecs_t period = activeConfig->getVsyncPeriod();
 
-    mPrimaryDispSync.reset();
-    mPrimaryDispSync.setPeriod(period);
+    mPrimaryDispSync->reset();
+    mPrimaryDispSync->setPeriod(period);
 
     if (!mPrimaryHWVsyncEnabled) {
-        mPrimaryDispSync.beginResync();
+        mPrimaryDispSync->beginResync();
         mEventControlThread->setVsyncEnabled(true);
         mPrimaryHWVsyncEnabled = true;
     }
@@ -1332,7 +1339,7 @@
     Mutex::Autolock _l(mHWVsyncLock);
     if (mPrimaryHWVsyncEnabled) {
         mEventControlThread->setVsyncEnabled(false);
-        mPrimaryDispSync.endResync();
+        mPrimaryDispSync->endResync();
         mPrimaryHWVsyncEnabled = false;
     }
     if (makeUnavailable) {
@@ -1377,7 +1384,7 @@
     { // Scope for the lock
         Mutex::Autolock _l(mHWVsyncLock);
         if (mPrimaryHWVsyncEnabled) {
-            needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
+            needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp);
         }
     }
 
@@ -1504,8 +1511,8 @@
 
     // The present fences returned from vr_hwc are not an accurate
     // representation of vsync times.
-    mPrimaryDispSync.setIgnorePresentFences(
-            getBE().mHwc->isUsingVrComposer() || !hasSyncFramework);
+    mPrimaryDispSync->setIgnorePresentFences(getBE().mHwc->isUsingVrComposer() ||
+                                             !hasSyncFramework);
 
     // Use phase of 0 since phase is not known.
     // Use latency of 0, which will snap to the ideal latency.
@@ -1768,8 +1775,8 @@
     auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
-    nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
-    nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
+    nsecs_t vsyncPhase = mPrimaryDispSync->computeNextRefresh(0);
+    nsecs_t vsyncInterval = mPrimaryDispSync->getPeriod();
 
     // We use the refreshStartTime which might be sampled a little later than
     // when we started doing work for this frame, but that should be okay
@@ -1792,7 +1799,7 @@
     });
 
     if (presentFenceTime->isValid()) {
-        if (mPrimaryDispSync.addPresentFence(presentFenceTime)) {
+        if (mPrimaryDispSync->addPresentFence(presentFenceTime)) {
             enableHardwareVsync();
         } else {
             disableHardwareVsync(false);
@@ -2765,7 +2772,7 @@
                 if (translucent) {
                     if (tr.preserveRects()) {
                         // transform the transparent region
-                        transparentRegion = tr.transform(s.activeTransparentRegion);
+                        transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
                     } else {
                         // transformation too complex, can't do the
                         // transparent region optimization.
@@ -2869,9 +2876,9 @@
     // Display is now waiting on Layer 1's frame, which is behind layer 0's
     // second frame. But layer 0's second frame could be waiting on display.
     mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (layer->hasQueuedFrame()) {
+        if (layer->hasReadyFrame()) {
             frameQueued = true;
-            if (layer->shouldPresentNow(mPrimaryDispSync)) {
+            if (layer->shouldPresentNow(*mPrimaryDispSync)) {
                 mLayersWithQueuedFrames.push_back(layer);
             } else {
                 layer->useEmptyDamage();
@@ -3399,7 +3406,7 @@
 
     // If we are deferring transaction, make sure to push the pending state, as otherwise the
     // pending state will also be deferred.
-    if (what & layer_state_t::eDeferTransaction) {
+    if (what & layer_state_t::eDeferTransaction_legacy) {
         layer->pushPendingState();
     }
 
@@ -3484,12 +3491,12 @@
         if (layer->setFlags(s.flags, s.mask))
             flags |= eTraversalNeeded;
     }
-    if (what & layer_state_t::eCropChanged) {
-        if (layer->setCrop(s.crop, !geometryAppliesWithResize))
+    if (what & layer_state_t::eCropChanged_legacy) {
+        if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize))
             flags |= eTraversalNeeded;
     }
-    if (what & layer_state_t::eFinalCropChanged) {
-        if (layer->setFinalCrop(s.finalCrop, !geometryAppliesWithResize))
+    if (what & layer_state_t::eFinalCropChanged_legacy) {
+        if (layer->setFinalCrop_legacy(s.finalCrop_legacy, !geometryAppliesWithResize))
             flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eLayerStackChanged) {
@@ -3511,15 +3518,15 @@
             flags |= eTransactionNeeded|eTraversalNeeded|eDisplayLayerStackChanged;
         }
     }
-    if (what & layer_state_t::eDeferTransaction) {
-        if (s.barrierHandle != nullptr) {
-            layer->deferTransactionUntil(s.barrierHandle, s.frameNumber);
-        } else if (s.barrierGbp != nullptr) {
-            const sp<IGraphicBufferProducer>& gbp = s.barrierGbp;
+    if (what & layer_state_t::eDeferTransaction_legacy) {
+        if (s.barrierHandle_legacy != nullptr) {
+            layer->deferTransactionUntil_legacy(s.barrierHandle_legacy, s.frameNumber_legacy);
+        } else if (s.barrierGbp_legacy != nullptr) {
+            const sp<IGraphicBufferProducer>& gbp = s.barrierGbp_legacy;
             if (authenticateSurfaceTextureLocked(gbp)) {
                 const auto& otherLayer =
                     (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
-                layer->deferTransactionUntil(otherLayer, s.frameNumber);
+                layer->deferTransactionUntil_legacy(otherLayer, s.frameNumber_legacy);
             } else {
                 ALOGE("Attempt to defer transaction to to an"
                         " unrecognized GraphicBufferProducer");
@@ -3550,6 +3557,37 @@
         // We don't trigger a traversal here because if no other state is
         // changed, we don't want this to cause any more work
     }
+    if (what & layer_state_t::eTransformChanged) {
+        if (layer->setTransform(s.transform)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eTransformToDisplayInverseChanged) {
+        if (layer->setTransformToDisplayInverse(s.transformToDisplayInverse))
+            flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eCropChanged) {
+        if (layer->setCrop(s.crop)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eBufferChanged) {
+        if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eAcquireFenceChanged) {
+        if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eDataspaceChanged) {
+        if (layer->setDataspace(s.dataspace)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eHdrMetadataChanged) {
+        if (layer->setHdrMetadata(s.hdrMetadata)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eSurfaceDamageRegionChanged) {
+        if (layer->setSurfaceDamageRegion(s.surfaceDamageRegion)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eApiChanged) {
+        if (layer->setApi(s.api)) flags |= eTraversalNeeded;
+    }
+    if (what & layer_state_t::eSidebandStreamChanged) {
+        if (layer->setSidebandStream(s.sidebandStream)) flags |= eTraversalNeeded;
+    }
     return flags;
 }
 
@@ -3592,12 +3630,14 @@
     String8 uniqueName = getUniqueLayerName(name);
 
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
-        case ISurfaceComposerClient::eFXSurfaceNormal:
-            result = createBufferLayer(client,
-                    uniqueName, w, h, flags, format,
-                    handle, gbp, &layer);
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            result = createBufferQueueLayer(client, uniqueName, w, h, flags, format, handle, gbp,
+                                            &layer);
 
             break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            result = createBufferStateLayer(client, uniqueName, w, h, flags, handle, &layer);
+            break;
         case ISurfaceComposerClient::eFXSurfaceColor:
             result = createColorLayer(client,
                     uniqueName, w, h, flags,
@@ -3659,10 +3699,11 @@
     return uniqueName;
 }
 
-status_t SurfaceFlinger::createBufferLayer(const sp<Client>& client,
-        const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
-        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
-{
+status_t SurfaceFlinger::createBufferQueueLayer(const sp<Client>& client, const String8& name,
+                                                uint32_t w, uint32_t h, uint32_t flags,
+                                                PixelFormat& format, sp<IBinder>* handle,
+                                                sp<IGraphicBufferProducer>* gbp,
+                                                sp<Layer>* outLayer) {
     // initialize the surfaces
     switch (format) {
     case PIXEL_FORMAT_TRANSPARENT:
@@ -3674,18 +3715,28 @@
         break;
     }
 
-    sp<BufferLayer> layer = new BufferLayer(this, client, name, w, h, flags);
-    status_t err = layer->setBuffers(w, h, format, flags);
+    sp<BufferQueueLayer> layer = new BufferQueueLayer(this, client, name, w, h, flags);
+    status_t err = layer->setDefaultBufferProperties(w, h, format);
     if (err == NO_ERROR) {
         *handle = layer->getHandle();
         *gbp = layer->getProducer();
         *outLayer = layer;
     }
 
-    ALOGE_IF(err, "createBufferLayer() failed (%s)", strerror(-err));
+    ALOGE_IF(err, "createBufferQueueLayer() failed (%s)", strerror(-err));
     return err;
 }
 
+status_t SurfaceFlinger::createBufferStateLayer(const sp<Client>& client, const String8& name,
+                                                uint32_t w, uint32_t h, uint32_t flags,
+                                                sp<IBinder>* handle, sp<Layer>* outLayer) {
+    sp<BufferStateLayer> layer = new BufferStateLayer(this, client, name, w, h, flags);
+    *handle = layer->getHandle();
+    *outLayer = layer;
+
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::createColorLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags,
         sp<IBinder>* handle, sp<Layer>* outLayer)
@@ -3920,7 +3971,7 @@
             if ((index < numArgs) &&
                     (args[index] == String16("--dispsync"))) {
                 index++;
-                mPrimaryDispSync.dump(result);
+                mPrimaryDispSync->dump(result);
                 dumpAll = false;
             }
 
@@ -4703,7 +4754,7 @@
             // Needs to be shifted to proper binder interface when we productize
             case 1016: {
                 n = data.readInt32();
-                mPrimaryDispSync.setRefreshSkipCount(n);
+                mPrimaryDispSync->setRefreshSkipCount(n);
                 return NO_ERROR;
             }
             case 1017: {
@@ -4863,10 +4914,12 @@
         const Transform& getTransform() const override { return mTransform; }
         Rect getBounds() const override {
             const Layer::State& layerState(mLayer->getDrawingState());
-            return Rect(layerState.active.w, layerState.active.h);
+            return Rect(mLayer->getActiveWidth(layerState), mLayer->getActiveHeight(layerState));
         }
-        int getHeight() const override { return mLayer->getDrawingState().active.h; }
-        int getWidth() const override { return mLayer->getDrawingState().active.w; }
+        int getHeight() const override {
+            return mLayer->getActiveHeight(mLayer->getDrawingState());
+        }
+        int getWidth() const override { return mLayer->getActiveWidth(mLayer->getDrawingState()); }
         bool isSecure() const override { return false; }
         bool needsFiltering() const override { return false; }
         Rect getSourceCrop() const override {
@@ -4934,12 +4987,12 @@
     Rect crop(sourceCrop);
     if (sourceCrop.width() <= 0) {
         crop.left = 0;
-        crop.right = parent->getCurrentState().active.w;
+        crop.right = parent->getActiveWidth(parent->getCurrentState());
     }
 
     if (sourceCrop.height() <= 0) {
         crop.top = 0;
-        crop.bottom = parent->getCurrentState().active.h;
+        crop.bottom = parent->getActiveHeight(parent->getCurrentState());
     }
 
     int32_t reqWidth = crop.width() * frameScale;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e107f42..12f4185 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -355,6 +355,8 @@
     friend class impl::EventThread;
     friend class Layer;
     friend class BufferLayer;
+    friend class BufferQueueLayer;
+    friend class BufferStateLayer;
     friend class MonitoredProducer;
 
     // For unit tests
@@ -529,10 +531,14 @@
             int32_t windowType, int32_t ownerUid, sp<IBinder>* handle,
             sp<IGraphicBufferProducer>* gbp, sp<Layer>* parent);
 
-    status_t createBufferLayer(const sp<Client>& client, const String8& name,
-            uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
-            sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
-            sp<Layer>* outLayer);
+    status_t createBufferQueueLayer(const sp<Client>& client, const String8& name, uint32_t w,
+                                    uint32_t h, uint32_t flags, PixelFormat& format,
+                                    sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp,
+                                    sp<Layer>* outLayer);
+
+    status_t createBufferStateLayer(const sp<Client>& client, const String8& name, uint32_t w,
+                                    uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
+                                    sp<Layer>* outLayer);
 
     status_t createColorLayer(const sp<Client>& client, const String8& name,
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
@@ -847,7 +853,7 @@
     // these are thread safe
     mutable std::unique_ptr<MessageQueue> mEventQueue{std::make_unique<impl::MessageQueue>()};
     FrameTracker mAnimFrameTracker;
-    DispSync mPrimaryDispSync;
+    std::unique_ptr<DispSync> mPrimaryDispSync;
     int mPrimaryDisplayOrientation = DisplayState::eOrientationDefault;
 
     // protected by mDestroyedLayerLock;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index e70506d..f504c13 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -30,6 +30,7 @@
 namespace android {
 
 // ----------------------------------------------------------------------------
+// TODO(marissaw): add new layer state values to SurfaceInterceptor
 
 SurfaceInterceptor::~SurfaceInterceptor() = default;
 
@@ -99,18 +100,20 @@
     transaction->set_animation(layer->mTransactionFlags & BnSurfaceComposer::eAnimation);
 
     const int32_t layerId(getLayerId(layer));
-    addPositionLocked(transaction, layerId, layer->mCurrentState.active.transform.tx(),
-            layer->mCurrentState.active.transform.ty());
+    addPositionLocked(transaction, layerId, layer->mCurrentState.active_legacy.transform.tx(),
+                      layer->mCurrentState.active_legacy.transform.ty());
     addDepthLocked(transaction, layerId, layer->mCurrentState.z);
     addAlphaLocked(transaction, layerId, layer->mCurrentState.color.a);
-    addTransparentRegionLocked(transaction, layerId, layer->mCurrentState.activeTransparentRegion);
+    addTransparentRegionLocked(transaction, layerId,
+                               layer->mCurrentState.activeTransparentRegion_legacy);
     addLayerStackLocked(transaction, layerId, layer->mCurrentState.layerStack);
-    addCropLocked(transaction, layerId, layer->mCurrentState.crop);
-    if (layer->mCurrentState.barrierLayer != nullptr) {
-        addDeferTransactionLocked(transaction, layerId, layer->mCurrentState.barrierLayer.promote(),
-                layer->mCurrentState.frameNumber);
+    addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
+    if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
+        addDeferTransactionLocked(transaction, layerId,
+                                  layer->mCurrentState.barrierLayer_legacy.promote(),
+                                  layer->mCurrentState.frameNumber_legacy);
     }
-    addFinalCropLocked(transaction, layerId, layer->mCurrentState.finalCrop);
+    addFinalCropLocked(transaction, layerId, layer->mCurrentState.finalCrop_legacy);
     addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
     addFlagsLocked(transaction, layerId, layer->mCurrentState.flags);
 }
@@ -353,25 +356,26 @@
     if (state.what & layer_state_t::eLayerStackChanged) {
         addLayerStackLocked(transaction, layerId, state.layerStack);
     }
-    if (state.what & layer_state_t::eCropChanged) {
-        addCropLocked(transaction, layerId, state.crop);
+    if (state.what & layer_state_t::eCropChanged_legacy) {
+        addCropLocked(transaction, layerId, state.crop_legacy);
     }
-    if (state.what & layer_state_t::eDeferTransaction) {
+    if (state.what & layer_state_t::eDeferTransaction_legacy) {
         sp<Layer> otherLayer = nullptr;
-        if (state.barrierHandle != nullptr) {
-            otherLayer = static_cast<Layer::Handle*>(state.barrierHandle.get())->owner.promote();
-        } else if (state.barrierGbp != nullptr) {
-            auto const& gbp = state.barrierGbp;
+        if (state.barrierHandle_legacy != nullptr) {
+            otherLayer =
+                    static_cast<Layer::Handle*>(state.barrierHandle_legacy.get())->owner.promote();
+        } else if (state.barrierGbp_legacy != nullptr) {
+            auto const& gbp = state.barrierGbp_legacy;
             if (mFlinger->authenticateSurfaceTextureLocked(gbp)) {
                 otherLayer = (static_cast<MonitoredProducer*>(gbp.get()))->getLayer();
             } else {
                 ALOGE("Attempt to defer transaction to to an unrecognized GraphicBufferProducer");
             }
         }
-        addDeferTransactionLocked(transaction, layerId, otherLayer, state.frameNumber);
+        addDeferTransactionLocked(transaction, layerId, otherLayer, state.frameNumber_legacy);
     }
-    if (state.what & layer_state_t::eFinalCropChanged) {
-        addFinalCropLocked(transaction, layerId, state.finalCrop);
+    if (state.what & layer_state_t::eFinalCropChanged_legacy) {
+        addFinalCropLocked(transaction, layerId, state.finalCrop_legacy);
     }
     if (state.what & layer_state_t::eOverrideScalingModeChanged) {
         addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
@@ -422,8 +426,8 @@
     SurfaceCreation* creation(increment->mutable_surface_creation());
     creation->set_id(getLayerId(layer));
     creation->set_name(getLayerName(layer));
-    creation->set_w(layer->mCurrentState.active.w);
-    creation->set_h(layer->mCurrentState.active.h);
+    creation->set_w(layer->mCurrentState.active_legacy.w);
+    creation->set_h(layer->mCurrentState.active_legacy.h);
 }
 
 void SurfaceInterceptor::addSurfaceDeletionLocked(Increment* increment,
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 135d2af..8ac2c87 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -320,11 +320,11 @@
 }
 
 void SurfaceInterceptorTest::cropUpdate(Transaction& t) {
-    t.setCrop(mBGSurfaceControl, CROP_UPDATE);
+    t.setCrop_legacy(mBGSurfaceControl, CROP_UPDATE);
 }
 
 void SurfaceInterceptorTest::finalCropUpdate(Transaction& t) {
-    t.setFinalCrop(mBGSurfaceControl, CROP_UPDATE);
+    t.setFinalCrop_legacy(mBGSurfaceControl, CROP_UPDATE);
 }
 
 void SurfaceInterceptorTest::matrixUpdate(Transaction& t) {
@@ -357,7 +357,8 @@
 }
 
 void SurfaceInterceptorTest::deferredTransactionUpdate(Transaction& t) {
-    t.deferTransactionUntil(mBGSurfaceControl, mBGSurfaceControl->getHandle(), DEFERRED_UPDATE);
+    t.deferTransactionUntil_legacy(mBGSurfaceControl, mBGSurfaceControl->getHandle(),
+                                   DEFERRED_UPDATE);
 }
 
 void SurfaceInterceptorTest::displayCreation(Transaction&) {
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 5108279..bde6614 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -62,38 +62,28 @@
 const Color Color::BLACK{0, 0, 0, 255};
 const Color Color::TRANSPARENT{0, 0, 0, 0};
 
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
 std::ostream& operator<<(std::ostream& os, const Color& color) {
     os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
     return os;
 }
 
 // Fill a region with the specified color.
-void fillBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect, const Color& color) {
-    int32_t x = rect.left;
-    int32_t y = rect.top;
-    int32_t width = rect.right - rect.left;
-    int32_t height = rect.bottom - rect.top;
-
-    if (x < 0) {
-        width += x;
-        x = 0;
-    }
-    if (y < 0) {
-        height += y;
-        y = 0;
-    }
-    if (x + width > buffer.width) {
-        x = std::min(x, buffer.width);
-        width = buffer.width - x;
-    }
-    if (y + height > buffer.height) {
-        y = std::min(y, buffer.height);
-        height = buffer.height - y;
+void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
+                                  const Color& color) {
+    Rect r(0, 0, buffer.width, buffer.height);
+    if (!r.intersect(rect, &r)) {
+        return;
     }
 
-    for (int32_t j = 0; j < height; j++) {
-        uint8_t* dst = static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (y + j) + x) * 4;
-        for (int32_t i = 0; i < width; i++) {
+    int32_t width = r.right - r.left;
+    int32_t height = r.bottom - r.top;
+
+    for (int32_t row = 0; row < height; row++) {
+        uint8_t* dst =
+                static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4;
+        for (int32_t column = 0; column < width; column++) {
             dst[0] = color.r;
             dst[1] = color.g;
             dst[2] = color.b;
@@ -103,6 +93,33 @@
     }
 }
 
+// Fill a region with the specified color.
+void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect, const Color& color) {
+    Rect r(0, 0, buffer->width, buffer->height);
+    if (!r.intersect(rect, &r)) {
+        return;
+    }
+
+    int32_t width = r.right - r.left;
+    int32_t height = r.bottom - r.top;
+
+    uint8_t* pixels;
+    buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                 reinterpret_cast<void**>(&pixels));
+
+    for (int32_t row = 0; row < height; row++) {
+        uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
+        for (int32_t column = 0; column < width; column++) {
+            dst[0] = color.r;
+            dst[1] = color.g;
+            dst[2] = color.b;
+            dst[3] = color.a;
+            dst += 4;
+        }
+    }
+    buffer->unlock();
+}
+
 // Check if a region has the specified color.
 void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect,
                        const Color& color, uint8_t tolerance) {
@@ -301,8 +318,8 @@
         ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
     }
 
-    sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
-                                   uint32_t flags = 0) {
+    virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+                                           uint32_t flags = 0) {
         auto layer =
                 mClient->createSurface(String8(name), width, height, PIXEL_FORMAT_RGBA_8888, flags);
         EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
@@ -319,7 +336,7 @@
         return layer;
     }
 
-    ANativeWindow_Buffer getLayerBuffer(const sp<SurfaceControl>& layer) {
+    ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
         // wait for previous transactions (such as setSize) to complete
         Transaction().apply(true);
 
@@ -329,35 +346,103 @@
         return buffer;
     }
 
-    void postLayerBuffer(const sp<SurfaceControl>& layer) {
+    void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
         ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
 
         // wait for the newly posted buffer to be latched
         waitForLayerBuffers();
     }
 
-    void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color) {
+    virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+                                           int32_t bufferWidth, int32_t bufferHeight) {
         ANativeWindow_Buffer buffer;
-        ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
-        fillBufferColor(buffer, Rect(0, 0, buffer.width, buffer.height), color);
-        postLayerBuffer(layer);
+        ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+        fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
+        postBufferQueueLayerBuffer(layer);
     }
 
-    void fillLayerQuadrant(const sp<SurfaceControl>& layer, const Color& topLeft,
+    virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+                                           int32_t bufferWidth, int32_t bufferHeight) {
+        sp<GraphicBuffer> buffer =
+                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                          BufferUsage::COMPOSER_OVERLAY,
+                                  "test");
+        fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
+        Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
+    }
+
+    void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
+                        int32_t bufferWidth, int32_t bufferHeight) {
+        switch (mLayerType) {
+            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+                fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
+                break;
+            case ISurfaceComposerClient::eFXSurfaceBufferState:
+                fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight);
+                break;
+            default:
+                ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+        }
+    }
+
+    void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer,
+                           int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft,
                            const Color& topRight, const Color& bottomLeft,
                            const Color& bottomRight) {
+        switch (mLayerType) {
+            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+                fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+                                             bottomLeft, bottomRight);
+                break;
+            case ISurfaceComposerClient::eFXSurfaceBufferState:
+                fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+                                             bottomLeft, bottomRight);
+                break;
+            default:
+                ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+        }
+    }
+
+    virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+                                              int32_t bufferHeight, const Color& topLeft,
+                                              const Color& topRight, const Color& bottomLeft,
+                                              const Color& bottomRight) {
         ANativeWindow_Buffer buffer;
-        ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
-        ASSERT_TRUE(buffer.width % 2 == 0 && buffer.height % 2 == 0);
+        ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+        ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
 
-        const int32_t halfW = buffer.width / 2;
-        const int32_t halfH = buffer.height / 2;
-        fillBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
-        fillBufferColor(buffer, Rect(halfW, 0, buffer.width, halfH), topRight);
-        fillBufferColor(buffer, Rect(0, halfH, halfW, buffer.height), bottomLeft);
-        fillBufferColor(buffer, Rect(halfW, halfH, buffer.width, buffer.height), bottomRight);
+        const int32_t halfW = bufferWidth / 2;
+        const int32_t halfH = bufferHeight / 2;
+        fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+        fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
+        fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
+        fillANativeWindowBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight),
+                                     bottomRight);
 
-        postLayerBuffer(layer);
+        postBufferQueueLayerBuffer(layer);
+    }
+
+    virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+                                              int32_t bufferHeight, const Color& topLeft,
+                                              const Color& topRight, const Color& bottomLeft,
+                                              const Color& bottomRight) {
+        sp<GraphicBuffer> buffer =
+                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                          BufferUsage::COMPOSER_OVERLAY,
+                                  "test");
+
+        ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
+
+        const int32_t halfW = bufferWidth / 2;
+        const int32_t halfH = bufferHeight / 2;
+        fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+        fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
+        fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
+        fillGraphicBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight);
+
+        Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
     }
 
     sp<ScreenCapture> screenshot() {
@@ -376,6 +461,10 @@
     // leave room for ~256 layers
     const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
 
+    void setPositionWithResizeHelper(uint32_t layerType);
+    void setSizeBasicHelper(uint32_t layerType);
+    void setMatrixWithResizeHelper(uint32_t layerType);
+
 private:
     void SetUpDisplay() {
         mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain);
@@ -404,10 +493,48 @@
     int32_t mBufferPostDelay;
 };
 
-TEST_F(LayerTransactionTest, SetPositionBasic) {
+class LayerTypeTransactionTest : public LayerTransactionTest,
+                                 public ::testing::WithParamInterface<uint32_t> {
+public:
+    LayerTypeTransactionTest() { mLayerType = GetParam(); }
+
+    sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+                                   uint32_t flags = 0) override {
+        // if the flags already have a layer type specified, return an error
+        if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
+            return nullptr;
+        }
+        return LayerTransactionTest::createLayer(name, width, height, flags | mLayerType);
+    }
+
+    void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth,
+                        int32_t bufferHeight) {
+        ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color,
+                                                                     bufferWidth, bufferHeight));
+    }
+
+    void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+                           int32_t bufferHeight, const Color& topLeft, const Color& topRight,
+                           const Color& bottomLeft, const Color& bottomRight) {
+        ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer,
+                                                                        bufferWidth, bufferHeight,
+                                                                        topLeft, topRight,
+                                                                        bottomLeft, bottomRight));
+    }
+
+protected:
+    uint32_t mLayerType;
+};
+
+INSTANTIATE_TEST_CASE_P(
+        LayerTypeTransactionTests, LayerTypeTransactionTest,
+        ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+                          static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
+
+TEST_P(LayerTypeTransactionTest, SetPositionBasic) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     {
         SCOPED_TRACE("default position");
@@ -425,10 +552,10 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetPositionRounding) {
+TEST_P(LayerTypeTransactionTest, SetPositionRounding) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     // GLES requires only 4 bits of subpixel precision during rasterization
     // XXX GLES composition does not match HWC composition due to precision
@@ -447,10 +574,10 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetPositionOutOfBounds) {
+TEST_P(LayerTypeTransactionTest, SetPositionOutOfBounds) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     Transaction().setPosition(layer, -32, -32).apply();
     {
@@ -465,10 +592,10 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetPositionPartiallyOutOfBounds) {
+TEST_P(LayerTypeTransactionTest, SetPositionPartiallyOutOfBounds) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     // partially out of bounds
     Transaction().setPosition(layer, -30, -30).apply();
@@ -486,10 +613,10 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetPositionWithResize) {
+void LayerTransactionTest::setPositionWithResizeHelper(uint32_t layerType) {
     sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
 
     // setPosition is applied immediately by default, with or without resize
     // pending
@@ -497,21 +624,43 @@
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
-        shot->expectColor(Rect(5, 10, 37, 42), Color::RED);
-        shot->expectBorder(Rect(5, 10, 37, 42), Color::BLACK);
+        Rect rect;
+        switch (layerType) {
+            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+                rect = {5, 10, 37, 42};
+                break;
+            case ISurfaceComposerClient::eFXSurfaceBufferState:
+                rect = {5, 10, 69, 74};
+                break;
+            default:
+                ASSERT_FALSE(true) << "Unsupported layer type";
+        }
+
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("resize applied");
         screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
     }
 }
 
-TEST_F(LayerTransactionTest, SetPositionWithNextResize) {
+TEST_F(LayerTransactionTest, SetPositionWithResize_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(
+            setPositionWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_F(LayerTransactionTest, SetPositionWithResize_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(
+            setPositionWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_F(LayerTransactionTest, SetPositionWithNextResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // request setPosition to be applied with the next resize
     Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply();
@@ -533,17 +682,17 @@
     }
 
     // finally resize and latch the buffer
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("new position applied");
         screenshot()->expectColor(Rect(15, 20, 79, 84), Color::RED);
     }
 }
 
-TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow) {
+TEST_F(LayerTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // setPosition is not immediate even with SCALE_TO_WINDOW override
     Transaction()
@@ -557,27 +706,38 @@
         screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("new position applied");
         screenshot()->expectColor(Rect(5, 10, 69, 74), Color::RED);
     }
 }
 
-TEST_F(LayerTransactionTest, SetSizeBasic) {
+void LayerTransactionTest::setSizeBasicHelper(uint32_t layerType) {
     sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
 
     Transaction().setSize(layer, 64, 64).apply();
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+        Rect rect;
+        switch (layerType) {
+            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+                rect = {0, 0, 32, 32};
+                break;
+            case ISurfaceComposerClient::eFXSurfaceBufferState:
+                rect = {0, 0, 64, 64};
+                break;
+            default:
+                ASSERT_FALSE(true) << "Unsupported layer type";
+        }
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("resize applied");
         auto shot = screenshot();
@@ -586,14 +746,22 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetSizeInvalid) {
+TEST_F(LayerTransactionTest, SetSizeBasic_BufferQueue) {
+    setSizeBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue);
+}
+
+TEST_F(LayerTransactionTest, SetSizeBasic_BufferState) {
+    setSizeBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState);
+}
+
+TEST_P(LayerTypeTransactionTest, SetSizeInvalid) {
     // cannot test robustness against invalid sizes (zero or really huge)
 }
 
-TEST_F(LayerTransactionTest, SetSizeWithScaleToWindow) {
+TEST_P(LayerTypeTransactionTest, SetSizeWithScaleToWindow) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
     Transaction()
@@ -603,13 +771,13 @@
     screenshot()->expectColor(Rect(0, 0, 64, 64), Color::RED);
 }
 
-TEST_F(LayerTransactionTest, SetZBasic) {
+TEST_P(LayerTypeTransactionTest, SetZBasic) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
     ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
 
     Transaction().setLayer(layerR, mLayerZBase + 1).apply();
     {
@@ -624,13 +792,13 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetZNegative) {
+TEST_P(LayerTypeTransactionTest, SetZNegative) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
     ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
 
     Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
     {
@@ -649,13 +817,13 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetRelativeZBasic) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZBasic) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
     ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
 
     Transaction()
             .setPosition(layerG, 16, 16)
@@ -677,16 +845,16 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetRelativeZNegative) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
     sp<SurfaceControl> layerB;
     ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
 
     // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
     Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
@@ -697,16 +865,16 @@
     screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
 }
 
-TEST_F(LayerTransactionTest, SetRelativeZGroup) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZGroup) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
     sp<SurfaceControl> layerB;
     ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
 
     // layerR = 0, layerG = layerR + 3, layerB = 2
     Transaction()
@@ -764,14 +932,14 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetRelativeZBug64572777) {
+TEST_P(LayerTypeTransactionTest, SetRelativeZBug64572777) {
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
 
     ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
 
     Transaction()
             .setPosition(layerG, 16, 16)
@@ -783,10 +951,10 @@
     screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
 
-TEST_F(LayerTransactionTest, SetFlagsHidden) {
+TEST_P(LayerTypeTransactionTest, SetFlagsHidden) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
     {
@@ -801,14 +969,14 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetFlagsOpaque) {
+TEST_P(LayerTypeTransactionTest, SetFlagsOpaque) {
     const Color translucentRed = {100, 0, 0, 100};
     sp<SurfaceControl> layerR;
     sp<SurfaceControl> layerG;
     ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32));
     ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
 
     Transaction()
             .setLayer(layerR, mLayerZBase + 1)
@@ -827,10 +995,10 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetFlagsSecure) {
+TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     sp<ISurfaceComposer> composer = ComposerService::getComposerService();
     sp<GraphicBuffer> outBuffer;
@@ -847,19 +1015,19 @@
                                       false));
 }
 
-TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic) {
+TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
     const Rect top(0, 0, 32, 16);
     const Rect bottom(0, 16, 32, 32);
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
 
     ANativeWindow_Buffer buffer;
-    ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
-    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::TRANSPARENT));
-    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::RED));
     // setTransparentRegionHint always applies to the following buffer
     Transaction().setTransparentRegionHint(layer, Region(top)).apply();
-    ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
     {
         SCOPED_TRACE("top transparent");
         auto shot = screenshot();
@@ -875,10 +1043,10 @@
         shot->expectColor(bottom, Color::RED);
     }
 
-    ASSERT_NO_FATAL_FAILURE(buffer = getLayerBuffer(layer));
-    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, top, Color::RED));
-    ASSERT_NO_FATAL_FAILURE(fillBufferColor(buffer, bottom, Color::TRANSPARENT));
-    ASSERT_NO_FATAL_FAILURE(postLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
     {
         SCOPED_TRACE("bottom transparent");
         auto shot = screenshot();
@@ -887,7 +1055,58 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetTransparentRegionHintOutOfBounds) {
+TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferState) {
+    const Rect top(0, 0, 32, 16);
+    const Rect bottom(0, 16, 32, 32);
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+
+    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::RED));
+    Transaction()
+            .setTransparentRegionHint(layer, Region(top))
+            .setBuffer(layer, buffer)
+            .setSize(layer, 32, 32)
+            .apply();
+    {
+        SCOPED_TRACE("top transparent");
+        auto shot = screenshot();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::RED);
+    }
+
+    Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+    {
+        SCOPED_TRACE("transparent region hint intermediate");
+        auto shot = screenshot();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::BLACK);
+    }
+
+    buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                               BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                       BufferUsage::COMPOSER_OVERLAY,
+                               "test");
+
+    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
+    Transaction().setBuffer(layer, buffer).setSize(layer, 32, 32).apply();
+    {
+        SCOPED_TRACE("bottom transparent");
+        auto shot = screenshot();
+        shot->expectColor(top, Color::RED);
+        shot->expectColor(bottom, Color::BLACK);
+    }
+}
+
+TEST_P(LayerTypeTransactionTest, SetTransparentRegionHintOutOfBounds) {
     sp<SurfaceControl> layerTransparent;
     sp<SurfaceControl> layerR;
     ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
@@ -900,18 +1119,18 @@
             .setPosition(layerR, 16, 16)
             .setLayer(layerR, mLayerZBase + 1)
             .apply();
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerTransparent, Color::TRANSPARENT));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
     screenshot()->expectColor(Rect(16, 16, 48, 48), Color::RED);
 }
 
-TEST_F(LayerTransactionTest, SetAlphaBasic) {
+TEST_P(LayerTypeTransactionTest, SetAlphaBasic) {
     sp<SurfaceControl> layer1;
     sp<SurfaceControl> layer2;
     ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32));
     ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer1, {64, 0, 0, 255}));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer2, {0, 64, 0, 255}));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer1, {64, 0, 0, 255}, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer2, {0, 64, 0, 255}, 32, 32));
 
     Transaction()
             .setAlpha(layer1, 0.25f)
@@ -931,11 +1150,11 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetAlphaClamped) {
+TEST_P(LayerTypeTransactionTest, SetAlphaClamped) {
     const Color color = {64, 0, 0, 255};
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32));
 
     Transaction().setAlpha(layer, 2.0f).apply();
     {
@@ -954,7 +1173,7 @@
     sp<SurfaceControl> bufferLayer;
     sp<SurfaceControl> colorLayer;
     ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(
             colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
 
@@ -989,7 +1208,7 @@
     sp<SurfaceControl> bufferLayer;
     sp<SurfaceControl> colorLayer;
     ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(
             colorLayer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
 
@@ -1014,7 +1233,7 @@
     sp<SurfaceControl> colorLayer;
     ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
     ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
     ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer(
             "childWithColor", 32, 32, ISurfaceComposerClient::eFXSurfaceColor));
 
@@ -1034,20 +1253,20 @@
                               tolerance);
 }
 
-TEST_F(LayerTransactionTest, SetColorWithBuffer) {
+TEST_P(LayerTypeTransactionTest, SetColorWithBuffer) {
     sp<SurfaceControl> bufferLayer;
     ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
 
     // color is ignored
     Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
     screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
 }
 
-TEST_F(LayerTransactionTest, SetLayerStackBasic) {
+TEST_P(LayerTypeTransactionTest, SetLayerStackBasic) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
     {
@@ -1062,11 +1281,11 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetMatrixBasic) {
+TEST_P(LayerTypeTransactionTest, SetMatrixBasic) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
     ASSERT_NO_FATAL_FAILURE(
-            fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+            fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
 
     Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
     {
@@ -1104,11 +1323,11 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetMatrixRot45) {
+TEST_P(LayerTypeTransactionTest, SetMatrixRot45) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
     ASSERT_NO_FATAL_FAILURE(
-            fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+            fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
 
     const float rot = M_SQRT1_2; // 45 degrees
     const float trans = M_SQRT2 * 16.0f;
@@ -1127,31 +1346,52 @@
     shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
 }
 
-TEST_F(LayerTransactionTest, SetMatrixWithResize) {
+void LayerTransactionTest::setMatrixWithResizeHelper(uint32_t layerType) {
     sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 32, 32));
 
     // setMatrix is applied after any pending resize, unlike setPosition
     Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+        Rect rect;
+        switch (layerType) {
+            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+                rect = {0, 0, 32, 32};
+                break;
+            case ISurfaceComposerClient::eFXSurfaceBufferState:
+                rect = {0, 0, 128, 128};
+                break;
+            default:
+                ASSERT_FALSE(true) << "Unsupported layer type";
+        }
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer, Color::RED, 64, 64));
     {
         SCOPED_TRACE("resize applied");
         screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
     }
 }
 
-TEST_F(LayerTransactionTest, SetMatrixWithScaleToWindow) {
+TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(
+            setMatrixWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_F(LayerTransactionTest, SetMatrixWithResize_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(
+            setMatrixWithResizeHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerTypeTransactionTest, SetMatrixWithScaleToWindow) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
 
     // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
     Transaction()
@@ -1162,11 +1402,11 @@
     screenshot()->expectColor(Rect(0, 0, 128, 128), Color::RED);
 }
 
-TEST_F(LayerTransactionTest, SetOverrideScalingModeBasic) {
+TEST_P(LayerTypeTransactionTest, SetOverrideScalingModeBasic) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
     ASSERT_NO_FATAL_FAILURE(
-            fillLayerQuadrant(layer, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
+            fillLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN, Color::BLUE, Color::WHITE));
 
     // XXX SCALE_CROP is not respected; calling setSize and
     // setOverrideScalingMode in separate transactions does not work
@@ -1182,10 +1422,23 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropBasic) {
+TEST_F(LayerTransactionTest, SetCropBasic_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+    const Rect crop(8, 8, 24, 24);
+
+    Transaction().setCrop_legacy(layer, crop).apply();
+    auto shot = screenshot();
+    shot->expectColor(crop, Color::RED);
+    shot->expectBorder(crop, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
     const Rect crop(8, 8, 24, 24);
 
     Transaction().setCrop(layer, crop).apply();
@@ -1194,10 +1447,29 @@
     shot->expectBorder(crop, Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropEmpty) {
+TEST_F(LayerTransactionTest, SetCropEmpty_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("empty rect");
+        Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    {
+        SCOPED_TRACE("negative rect");
+        Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetCropEmpty_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
 
     {
         SCOPED_TRACE("empty rect");
@@ -1212,10 +1484,22 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropOutOfBounds) {
+TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropOutOfBounds_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
 
     Transaction().setCrop(layer, Rect(-128, -64, 128, 64)).apply();
     auto shot = screenshot();
@@ -1223,10 +1507,24 @@
     shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropWithTranslation) {
+TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    const Point position(32, 32);
+    const Rect crop(8, 8, 24, 24);
+    Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
+    auto shot = screenshot();
+    shot->expectColor(crop + position, Color::RED);
+    shot->expectBorder(crop + position, Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropWithTranslation_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
 
     const Point position(32, 32);
     const Rect crop(8, 8, 24, 24);
@@ -1236,10 +1534,26 @@
     shot->expectBorder(crop + position, Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropWithScale) {
+TEST_F(LayerTransactionTest, SetCropWithScale_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // crop is affected by matrix
+    Transaction()
+            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+            .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+            .apply();
+    auto shot = screenshot();
+    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetCropWithScale_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
 
     // crop is affected by matrix
     Transaction()
@@ -1251,13 +1565,13 @@
     shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropWithResize) {
+TEST_F(LayerTransactionTest, SetCropWithResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
-    // setCrop is applied immediately by default, with or without resize pending
-    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+    // setCrop_legacy is applied immediately by default, with or without resize pending
+    Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
@@ -1265,7 +1579,7 @@
         shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
     {
         SCOPED_TRACE("resize applied");
         auto shot = screenshot();
@@ -1274,19 +1588,46 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropWithNextResize) {
+TEST_F(LayerTransactionTest, SetCropWithResize_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    // setCrop_legacy is applied immediately by default, with or without resize pending
+    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+    {
+        SCOPED_TRACE("new buffer pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
+    {
+        SCOPED_TRACE("new buffer");
+        auto shot = screenshot();
+        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
-    // request setCrop to be applied with the next resize
-    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setGeometryAppliesWithResize(layer).apply();
+    // request setCrop_legacy to be applied with the next resize
+    Transaction()
+            .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+            .setGeometryAppliesWithResize(layer)
+            .apply();
     {
         SCOPED_TRACE("waiting for next resize");
         screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
     }
 
-    Transaction().setCrop(layer, Rect(4, 4, 12, 12)).apply();
+    Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
     {
         SCOPED_TRACE("pending crop modified");
         screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
@@ -1299,7 +1640,7 @@
     }
 
     // finally resize
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
     {
         SCOPED_TRACE("new crop applied");
         auto shot = screenshot();
@@ -1308,14 +1649,49 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow) {
+TEST_F(LayerTransactionTest, SetCropWithNextResize_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    // request setCrop_legacy to be applied with the next resize
+    Transaction().setCrop(layer, Rect(8, 8, 24, 24)).setGeometryAppliesWithResize(layer).apply();
+    {
+        SCOPED_TRACE("set crop 1");
+        screenshot()->expectColor(Rect(8, 8, 24, 24), Color::RED);
+    }
+
+    Transaction().setCrop(layer, Rect(4, 4, 12, 12)).apply();
+    {
+        SCOPED_TRACE("set crop 2");
+        screenshot()->expectColor(Rect(4, 4, 12, 12), Color::RED);
+    }
+
+    Transaction().setSize(layer, 16, 16).apply();
+    {
+        SCOPED_TRACE("resize");
+        screenshot()->expectColor(Rect(4, 4, 12, 12), Color::RED);
+    }
+
+    // finally resize
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
+    {
+        SCOPED_TRACE("new buffer");
+        auto shot = screenshot();
+        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
-    // setCrop is not immediate even with SCALE_TO_WINDOW override
+    // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override
     Transaction()
-            .setCrop(layer, Rect(4, 4, 12, 12))
+            .setCrop_legacy(layer, Rect(4, 4, 12, 12))
             .setSize(layer, 16, 16)
             .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
             .setGeometryAppliesWithResize(layer)
@@ -1329,7 +1705,7 @@
 
     // XXX crop is never latched without other geometry change (b/69315677)
     Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
     Transaction().setPosition(layer, 0, 0).apply();
     {
         SCOPED_TRACE("new crop applied");
@@ -1339,84 +1715,115 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropBasic) {
+TEST_F(LayerTransactionTest, SetCropWithNextResizeScaleToWindow_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    // all properties are applied immediate so setGeometryAppliesWithResize has no effect
+    Transaction()
+            .setCrop(layer, Rect(4, 4, 12, 12))
+            .setSize(layer, 16, 16)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .setGeometryAppliesWithResize(layer)
+            .apply();
+    {
+        SCOPED_TRACE("new crop pending");
+        auto shot = screenshot();
+        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+    }
+
+    Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 16, 16));
+    Transaction().setPosition(layer, 0, 0).apply();
+    {
+        SCOPED_TRACE("new crop applied");
+        auto shot = screenshot();
+        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
+        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetFinalCropBasic_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
     const Rect crop(8, 8, 24, 24);
 
     // same as in SetCropBasic
-    Transaction().setFinalCrop(layer, crop).apply();
+    Transaction().setFinalCrop_legacy(layer, crop).apply();
     auto shot = screenshot();
     shot->expectColor(crop, Color::RED);
     shot->expectBorder(crop, Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropEmpty) {
+TEST_F(LayerTransactionTest, SetFinalCropEmpty_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // same as in SetCropEmpty
     {
         SCOPED_TRACE("empty rect");
-        Transaction().setFinalCrop(layer, Rect(8, 8, 8, 8)).apply();
+        Transaction().setFinalCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
         screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
     }
 
     {
         SCOPED_TRACE("negative rect");
-        Transaction().setFinalCrop(layer, Rect(8, 8, 0, 0)).apply();
+        Transaction().setFinalCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
         screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
     }
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropOutOfBounds) {
+TEST_F(LayerTransactionTest, SetFinalCropOutOfBounds_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // same as in SetCropOutOfBounds
-    Transaction().setFinalCrop(layer, Rect(-128, -64, 128, 64)).apply();
+    Transaction().setFinalCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
     auto shot = screenshot();
     shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
     shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropWithTranslation) {
+TEST_F(LayerTransactionTest, SetFinalCropWithTranslation_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // final crop is applied post-translation
-    Transaction().setPosition(layer, 16, 16).setFinalCrop(layer, Rect(8, 8, 24, 24)).apply();
+    Transaction().setPosition(layer, 16, 16).setFinalCrop_legacy(layer, Rect(8, 8, 24, 24)).apply();
     auto shot = screenshot();
     shot->expectColor(Rect(16, 16, 24, 24), Color::RED);
     shot->expectBorder(Rect(16, 16, 24, 24), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropWithScale) {
+TEST_F(LayerTransactionTest, SetFinalCropWithScale_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // final crop is not affected by matrix
     Transaction()
             .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
-            .setFinalCrop(layer, Rect(8, 8, 24, 24))
+            .setFinalCrop_legacy(layer, Rect(8, 8, 24, 24))
             .apply();
     auto shot = screenshot();
     shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
     shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropWithResize) {
+TEST_F(LayerTransactionTest, SetFinalCropWithResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // same as in SetCropWithResize
-    Transaction().setFinalCrop(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+    Transaction().setFinalCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
     {
         SCOPED_TRACE("resize pending");
         auto shot = screenshot();
@@ -1424,7 +1831,7 @@
         shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
     }
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
     {
         SCOPED_TRACE("resize applied");
         auto shot = screenshot();
@@ -1433,14 +1840,14 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropWithNextResize) {
+TEST_F(LayerTransactionTest, SetFinalCropWithNextResize_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // same as in SetCropWithNextResize
     Transaction()
-            .setFinalCrop(layer, Rect(8, 8, 24, 24))
+            .setFinalCrop_legacy(layer, Rect(8, 8, 24, 24))
             .setGeometryAppliesWithResize(layer)
             .apply();
     {
@@ -1448,7 +1855,7 @@
         screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
     }
 
-    Transaction().setFinalCrop(layer, Rect(4, 4, 12, 12)).apply();
+    Transaction().setFinalCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
     {
         SCOPED_TRACE("pending final crop modified");
         screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
@@ -1461,7 +1868,7 @@
     }
 
     // finally resize
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
     {
         SCOPED_TRACE("new final crop applied");
         auto shot = screenshot();
@@ -1470,14 +1877,14 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetFinalCropWithNextResizeScaleToWindow) {
+TEST_F(LayerTransactionTest, SetFinalCropWithNextResizeScaleToWindow_BufferQueue) {
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
 
     // same as in SetCropWithNextResizeScaleToWindow
     Transaction()
-            .setFinalCrop(layer, Rect(4, 4, 12, 12))
+            .setFinalCrop_legacy(layer, Rect(4, 4, 12, 12))
             .setSize(layer, 16, 16)
             .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
             .setGeometryAppliesWithResize(layer)
@@ -1491,7 +1898,7 @@
 
     // XXX final crop is never latched without other geometry change (b/69315677)
     Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
     Transaction().setPosition(layer, 0, 0).apply();
     {
         SCOPED_TRACE("new final crop applied");
@@ -1501,6 +1908,282 @@
     }
 }
 
+TEST_F(LayerTransactionTest, SetBufferBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetBufferMultipleBuffers_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("set buffer 1");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
+
+    {
+        SCOPED_TRACE("set buffer 2");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("set buffer 3");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetBufferMultipleLayers_BufferState) {
+    sp<SurfaceControl> layer1;
+    ASSERT_NO_FATAL_FAILURE(
+            layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<SurfaceControl> layer2;
+    ASSERT_NO_FATAL_FAILURE(
+            layer2 = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
+
+    {
+        SCOPED_TRACE("set layer 1 buffer red");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
+
+    {
+        SCOPED_TRACE("set layer 2 buffer blue");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+        shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
+        shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
+    {
+        SCOPED_TRACE("set layer 1 buffer green");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+        shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+        shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::WHITE, 32, 32));
+
+    {
+        SCOPED_TRACE("set layer 2 buffer white");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
+        shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+        shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+    }
+}
+
+TEST_F(LayerTransactionTest, SetTransformRotate90_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90).apply();
+
+    screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+                                 Color::GREEN, true /* filtered */);
+}
+
+TEST_F(LayerTransactionTest, SetTransformFlipH_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H).apply();
+
+    screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+                                 Color::BLUE, true /* filtered */);
+}
+
+TEST_F(LayerTransactionTest, SetTransformFlipV_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction().setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V).apply();
+
+    screenshot()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+                                 Color::GREEN, true /* filtered */);
+}
+
+TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction().setTransformToDisplayInverse(layer, false).apply();
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::GREEN, 32, 32));
+
+    Transaction().setTransformToDisplayInverse(layer, true).apply();
+}
+
+TEST_F(LayerTransactionTest, SetFenceBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    sp<Fence> fence = new Fence(-1);
+
+    Transaction()
+            .setBuffer(layer, buffer)
+            .setAcquireFence(layer, fence)
+            .setSize(layer, 32, 32)
+            .apply();
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetDataspaceBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    Transaction()
+            .setBuffer(layer, buffer)
+            .setDataspace(layer, ui::Dataspace::UNKNOWN)
+            .setSize(layer, 32, 32)
+            .apply();
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetHdrMetadataBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    HdrMetadata hdrMetadata;
+    hdrMetadata.validTypes = 0;
+    Transaction()
+            .setBuffer(layer, buffer)
+            .setHdrMetadata(layer, hdrMetadata)
+            .setSize(layer, 32, 32)
+            .apply();
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    Region region;
+    region.set(32, 32);
+    Transaction()
+            .setBuffer(layer, buffer)
+            .setSurfaceDamageRegion(layer, region)
+            .setSize(layer, 32, 32)
+            .apply();
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetApiBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    Transaction()
+            .setBuffer(layer, buffer)
+            .setApi(layer, NATIVE_WINDOW_API_CPU)
+            .setSize(layer, 32, 32)
+            .apply();
+
+    auto shot = screenshot();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    // verify this doesn't cause a crash
+    Transaction().setSidebandStream(layer, nullptr).apply();
+}
+
 class LayerUpdateTest : public LayerTransactionTest {
 protected:
     virtual void SetUp() {
@@ -1649,8 +2332,8 @@
         asTransaction([&](Transaction& t) {
             t.setSize(mFGSurfaceControl, 64, 64);
             t.setPosition(mFGSurfaceControl, 64, 64);
-            t.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
-            t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+            t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+            t.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, -1, -1));
         });
 
         EXPECT_INITIAL_STATE("After restoring initial state");
@@ -1686,7 +2369,7 @@
     // Normally the crop applies immediately even while a resize is pending.
     asTransaction([&](Transaction& t) {
         t.setSize(mFGSurfaceControl, 128, 128);
-        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+        t.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
     });
 
     EXPECT_CROPPED_STATE("after setting crop (without geometryAppliesWithResize)");
@@ -1700,7 +2383,7 @@
     asTransaction([&](Transaction& t) {
         t.setSize(mFGSurfaceControl, 128, 128);
         t.setGeometryAppliesWithResize(mFGSurfaceControl);
-        t.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+        t.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
     });
 
     EXPECT_INITIAL_STATE("after setting crop (with geometryAppliesWithResize)");
@@ -1729,14 +2412,14 @@
     // set up two deferred transactions on different frames
     asTransaction([&](Transaction& t) {
         t.setAlpha(mFGSurfaceControl, 0.75);
-        t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
-                                mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+        t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                                       mSyncSurfaceControl->getSurface()->getNextFrameNumber());
     });
 
     asTransaction([&](Transaction& t) {
         t.setPosition(mFGSurfaceControl, 128, 128);
-        t.deferTransactionUntil(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
-                                mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+        t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                                       mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
     });
 
     {
@@ -1881,7 +2564,7 @@
         t.show(mChild);
         t.setPosition(mChild, 0, 0);
         t.setPosition(mFGSurfaceControl, 0, 0);
-        t.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+        t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
     });
 
     {
@@ -1897,7 +2580,7 @@
         t.show(mChild);
         t.setPosition(mChild, 0, 0);
         t.setPosition(mFGSurfaceControl, 0, 0);
-        t.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+        t.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
     });
 
     {
@@ -2166,8 +2849,8 @@
 
     // Show the child layer in a deferred transaction
     asTransaction([&](Transaction& t) {
-        t.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(),
-                                mFGSurfaceControl->getSurface()->getNextFrameNumber());
+        t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+                                       mFGSurfaceControl->getSurface()->getNextFrameNumber());
         t.show(mChild);
     });
 
@@ -2465,8 +3148,9 @@
 }
 
 TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
-
-    SurfaceComposerClient::Transaction().setCrop(mFGSurfaceControl, Rect(0, 0, 1, 1)).apply(true);
+    SurfaceComposerClient::Transaction()
+            .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
+            .apply(true);
 
     // Even though the parent is cropped out we should still capture the child.
     verify();
@@ -2565,8 +3249,8 @@
             mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
                                            0, redLayer.get());
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
 
     SurfaceComposerClient::Transaction()
             .setLayer(redLayer, INT32_MAX - 1)
@@ -2599,8 +3283,8 @@
             mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888,
                                            0, redLayer.get());
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(blueLayer, Color::BLUE));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
 
     SurfaceComposerClient::Transaction()
             .setLayer(redLayer, INT32_MAX - 1)
@@ -2632,7 +3316,7 @@
     sp<SurfaceControl> redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60,
                                                                  PIXEL_FORMAT_RGBA_8888, 0);
 
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(redLayer, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
 
     auto redLayerHandle = redLayer->getHandle();
     mComposerClient->destroySurface(redLayerHandle);
@@ -2651,9 +3335,9 @@
     void SetUp() override {
         LayerTransactionTest::SetUp();
         bgLayer = createLayer("BG layer", 20, 20);
-        fillLayerColor(bgLayer, Color::RED);
+        fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
         fgLayer = createLayer("FG layer", 20, 20);
-        fillLayerColor(fgLayer, Color::BLUE);
+        fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
         Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
         {
             SCOPED_TRACE("before anything");
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 070bd51..7fafab9 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -624,7 +624,7 @@
     {
         TransactionScope ts(*sFakeComposer);
         Rect cropRect(16, 16, 32, 32);
-        ts.setCrop(mFGSurfaceControl, cropRect);
+        ts.setCrop_legacy(mFGSurfaceControl, cropRect);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -639,7 +639,7 @@
     {
         TransactionScope ts(*sFakeComposer);
         Rect cropRect(32, 32, 32 + 64, 32 + 64);
-        ts.setFinalCrop(mFGSurfaceControl, cropRect);
+        ts.setFinalCrop_legacy(mFGSurfaceControl, cropRect);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -657,7 +657,7 @@
     {
         TransactionScope ts(*sFakeComposer);
         Rect cropRect(16, 16, 32, 32);
-        ts.setFinalCrop(mFGSurfaceControl, cropRect);
+        ts.setFinalCrop_legacy(mFGSurfaceControl, cropRect);
     }
     ASSERT_EQ(2, sFakeComposer->getFrameCount());
 
@@ -847,18 +847,16 @@
     {
         TransactionScope ts(*sFakeComposer);
         ts.setAlpha(mFGSurfaceControl, 0.75);
-        ts.deferTransactionUntil(mFGSurfaceControl, 
-                syncSurfaceControl->getHandle(),
-                syncSurfaceControl->getSurface()->getNextFrameNumber());
+        ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+                                        syncSurfaceControl->getSurface()->getNextFrameNumber());
     }
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
 
     {
         TransactionScope ts(*sFakeComposer);
         ts.setPosition(mFGSurfaceControl, 128, 128);
-        ts.deferTransactionUntil(mFGSurfaceControl,
-                syncSurfaceControl->getHandle(),
-                syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+        ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+                                        syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
     }
     EXPECT_EQ(4, sFakeComposer->getFrameCount());
     EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
@@ -981,7 +979,7 @@
         ts.show(mChild);
         ts.setPosition(mChild, 0, 0);
         ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
     }
     // NOTE: The foreground surface would be occluded by the child
     // now, but is included in the stack because the child is
@@ -1000,7 +998,7 @@
         ts.show(mChild);
         ts.setPosition(mChild, 0, 0);
         ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, 5, 5));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
     }
     auto referenceFrame = mBaseFrame;
     referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
@@ -1238,8 +1236,8 @@
     // Show the child layer in a deferred transaction
     {
         TransactionScope ts(*sFakeComposer);
-        ts.deferTransactionUntil(mChild, mFGSurfaceControl->getHandle(), 
-                                      mFGSurfaceControl->getSurface()->getNextFrameNumber());
+        ts.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+                                        mFGSurfaceControl->getSurface()->getNextFrameNumber());
         ts.show(mChild);
     }
 
@@ -1355,8 +1353,8 @@
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 64, 64);
         ts.setPosition(mFGSurfaceControl, 64, 64);
-        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 64, 64));
-        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, -1, -1));
     }
 };
 
@@ -1400,7 +1398,7 @@
     {
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 128, 128);
-        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
     }
 
     auto referenceFrame1 = mBaseFrame;
@@ -1414,7 +1412,7 @@
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 128, 128);
         ts.setGeometryAppliesWithResize(mFGSurfaceControl);
-        ts.setCrop(mFGSurfaceControl, Rect(0, 0, 63, 63));
+        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
@@ -1432,7 +1430,7 @@
     {
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 128, 128);
-        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
 
     auto referenceFrame1 = mBaseFrame;
@@ -1447,7 +1445,7 @@
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 128, 128);
         ts.setGeometryAppliesWithResize(mFGSurfaceControl);
-        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
@@ -1468,7 +1466,7 @@
     {
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 128, 128);
-        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
 
     auto referenceFrame1 = mBaseFrame;
@@ -1487,7 +1485,7 @@
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 128, 128);
         ts.setGeometryAppliesWithResize(mFGSurfaceControl);
-        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
@@ -1516,12 +1514,12 @@
         TransactionScope ts(*sFakeComposer);
         ts.setSize(mFGSurfaceControl, 128, 128);
         ts.setGeometryAppliesWithResize(mFGSurfaceControl);
-        ts.setFinalCrop(mFGSurfaceControl, Rect(64, 64, 127, 127));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(64, 64, 127, 127));
     }
 
     {
         TransactionScope ts(*sFakeComposer);
-        ts.setFinalCrop(mFGSurfaceControl, Rect(0, 0, -1, -1));
+        ts.setFinalCrop_legacy(mFGSurfaceControl, Rect(0, 0, -1, -1));
     }
     EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
 
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 95c54b8..8f1f5e5 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -27,6 +27,7 @@
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
         "mock/gui/MockGraphicBufferConsumer.cpp",
         "mock/gui/MockGraphicBufferProducer.cpp",
+        "mock/MockDispSync.cpp",
         "mock/MockEventControlThread.cpp",
         "mock/MockEventThread.cpp",
         "mock/MockMessageQueue.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 58d3879..508875d 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -25,6 +25,7 @@
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockDispSync.h"
 #include "mock/MockEventControlThread.h"
 #include "mock/MockEventThread.h"
 #include "mock/MockMessageQueue.h"
@@ -119,6 +120,7 @@
     Hwc2::mock::Composer* mComposer = nullptr;
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
     mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
 
     // These mocks are created only when expected to be created via a factory.
     sp<mock::GraphicBufferConsumer> mConsumer;
@@ -154,6 +156,7 @@
     mFlinger.mutableEventQueue().reset(mMessageQueue);
     mFlinger.setupRenderEngine(std::unique_ptr<RE::RenderEngine>(mRenderEngine));
     mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
+    mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
 
     injectMockComposer(0);
 }
@@ -961,6 +964,9 @@
     // The call clears the current render engine surface
     EXPECT_CALL(*mRenderEngine, resetCurrentSurface());
 
+    // The call ends any display resyncs
+    EXPECT_CALL(*mPrimaryDispSync, endResync()).Times(1);
+
     // --------------------------------------------------------------------
     // Invocation
 
@@ -2400,6 +2406,24 @@
     }
 };
 
+struct DispSyncIsSupportedVariant {
+    static void setupBeginResyncCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mPrimaryDispSync, reset()).Times(1);
+        EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1);
+        EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1);
+    }
+
+    static void setupEndResyncCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mPrimaryDispSync, endResync()).Times(1);
+    }
+};
+
+struct DispSyncNotSupportedVariant {
+    static void setupBeginResyncCallExpectations(DisplayTransactionTest* /* test */) {}
+
+    static void setupEndResyncCallExpectations(DisplayTransactionTest* /* test */) {}
+};
+
 // --------------------------------------------------------------------
 // Note:
 //
@@ -2421,6 +2445,7 @@
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
         Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::DispSync::setupBeginResyncCallExpectations(test);
         Case::setupRepaintEverythingCallExpectations(test);
     }
 
@@ -2450,6 +2475,7 @@
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+        Case::DispSync::setupEndResyncCallExpectations(test);
         Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
     }
 
@@ -2485,6 +2511,7 @@
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::DispSync::setupBeginResyncCallExpectations(test);
         Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
     }
 };
@@ -2503,6 +2530,7 @@
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::DispSync::setupBeginResyncCallExpectations(test);
         Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
     }
 };
@@ -2512,6 +2540,7 @@
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+        Case::DispSync::setupEndResyncCallExpectations(test);
         Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
     }
 };
@@ -2534,11 +2563,12 @@
 // --------------------------------------------------------------------
 
 template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
-          typename TransitionVariant>
+          typename DispSyncVariant, typename TransitionVariant>
 struct DisplayPowerCase {
     using Display = DisplayVariant;
     using Doze = DozeVariant;
     using EventThread = EventThreadVariant;
+    using DispSync = DispSyncVariant;
     using Transition = TransitionVariant;
 
     static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
@@ -2586,15 +2616,16 @@
 // In addition to having event thread support, we emulate doze support.
 template <typename TransitionVariant>
 using PrimaryDisplayPowerCase = DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant,
-                                                 EventThreadIsSupportedVariant, TransitionVariant>;
+                                                 EventThreadIsSupportedVariant,
+                                                 DispSyncIsSupportedVariant, TransitionVariant>;
 
 // A sample configuration for the external display.
 // In addition to not having event thread support, we emulate not having doze
 // support.
 template <typename TransitionVariant>
-using ExternalDisplayPowerCase =
-        DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
-                         EventThreadNotSupportedVariant, TransitionVariant>;
+using ExternalDisplayPowerCase = DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant,
+                                                  EventThreadNotSupportedVariant,
+                                                  DispSyncNotSupportedVariant, TransitionVariant>;
 
 class SetPowerModeInternalTest : public DisplayTransactionTest {
 public:
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 5031148..9df4264 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -126,6 +126,7 @@
     auto& mutableInterceptor() { return mFlinger->mInterceptor; }
     auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
     auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
+    auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
     auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
@@ -144,6 +145,7 @@
         mutableEventQueue().reset();
         mutableEventThread().reset();
         mutableInterceptor().reset();
+        mutablePrimaryDispSync().reset();
         mFlinger->getBE().mHwc.reset();
         mFlinger->getBE().mRenderEngine.reset();
     }
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
new file mode 100644
index 0000000..2f7e5ea
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2018 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 "mock/MockDispSync.h"
+
+namespace android {
+namespace mock {
+
+// Explicit default instantiation is recommended.
+DispSync::DispSync() = default;
+DispSync::~DispSync() = default;
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
new file mode 100644
index 0000000..4a466ef
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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 <gmock/gmock.h>
+
+#include <utils/String8.h>
+#include "DispSync.h"
+
+namespace android {
+namespace mock {
+
+class DispSync : public android::DispSync {
+public:
+    DispSync();
+    ~DispSync() override;
+
+    MOCK_METHOD0(reset, void());
+    MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
+    MOCK_METHOD0(beginResync, void());
+    MOCK_METHOD1(addResyncSample, bool(nsecs_t));
+    MOCK_METHOD0(endResync, void());
+    MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD0(getPeriod, nsecs_t());
+    MOCK_METHOD1(setRefreshSkipCount, void(int));
+    MOCK_METHOD3(addEventListener, status_t(const char*, nsecs_t, Callback*));
+    MOCK_METHOD1(removeEventListener, status_t(Callback*));
+    MOCK_METHOD2(changePhaseOffset, status_t(Callback*, nsecs_t));
+    MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
+    MOCK_METHOD1(setIgnorePresentFences, void(bool));
+
+    MOCK_CONST_METHOD1(dump, void(String8&));
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 7caf864..7814d32 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -37,6 +37,8 @@
     MOCK_METHOD0(createImage, std::unique_ptr<RE::Image>());
     MOCK_CONST_METHOD0(primeCache, void());
     MOCK_METHOD1(dump, void(String8&));
+    MOCK_CONST_METHOD0(useNativeFenceSync, bool());
+    MOCK_CONST_METHOD0(useWaitSync, bool());
     MOCK_CONST_METHOD0(isCurrent, bool());
     MOCK_METHOD1(setCurrentSurface, bool(const RE::Surface&));
     MOCK_METHOD0(resetCurrentSurface, void());
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 6122846..499a8f6 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -13,11 +13,12 @@
 // limitations under the License.
 
 sourceFiles = [
+    "buffer_channel.cpp",
     "buffer_hub.cpp",
+    "buffer_node.cpp",
     "bufferhubd.cpp",
     "consumer_channel.cpp",
     "producer_channel.cpp",
-    "detached_buffer_channel.cpp",
     "consumer_queue_channel.cpp",
     "producer_queue_channel.cpp",
 ]
diff --git a/services/vr/bufferhubd/buffer_channel.cpp b/services/vr/bufferhubd/buffer_channel.cpp
new file mode 100644
index 0000000..2150d62
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.cpp
@@ -0,0 +1,206 @@
+#include "buffer_channel.h"
+#include "producer_channel.h"
+
+using android::pdx::BorrowedHandle;
+using android::pdx::ErrorStatus;
+using android::pdx::Message;
+using android::pdx::RemoteChannelHandle;
+using android::pdx::Status;
+using android::pdx::rpc::DispatchRemoteMethod;
+
+namespace android {
+namespace dvr {
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+                             int channel_id, IonBuffer buffer,
+                             IonBuffer metadata_buffer,
+                             size_t user_metadata_size)
+    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+      buffer_node_(std::make_shared<BufferNode>(
+          std::move(buffer), std::move(metadata_buffer), user_metadata_size)),
+      buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+  buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+                             uint32_t width, uint32_t height,
+                             uint32_t layer_count, uint32_t format,
+                             uint64_t usage, size_t user_metadata_size)
+    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
+      buffer_node_(std::make_shared<BufferNode>(
+          width, height, layer_count, format, usage, user_metadata_size)),
+      buffer_state_bit_(BufferHubDefs::FindFirstClearedBit()) {
+  buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::BufferChannel(BufferHubService* service, int buffer_id,
+                             int channel_id,
+                             std::shared_ptr<BufferNode> buffer_node,
+                             uint64_t buffer_state_bit)
+    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
+      buffer_node_(buffer_node),
+      buffer_state_bit_(buffer_state_bit) {
+  buffer_node_->set_buffer_state_bit(buffer_state_bit_);
+}
+
+BufferChannel::~BufferChannel() {
+  ALOGD_IF(TRACE, "BufferChannel::~BufferChannel: channel_id=%d buffer_id=%d.",
+           channel_id(), buffer_id());
+  Hangup();
+}
+
+BufferHubChannel::BufferInfo BufferChannel::GetBufferInfo() const {
+  return BufferInfo(
+      buffer_id(), /*consumer_count=*/0, buffer_node_->buffer().width(),
+      buffer_node_->buffer().height(), buffer_node_->buffer().layer_count(),
+      buffer_node_->buffer().format(), buffer_node_->buffer().usage(),
+      /*pending_count=*/0, /*state=*/0, /*signaled_mask=*/0,
+      /*index=*/0);
+}
+
+void BufferChannel::HandleImpulse(Message& /*message*/) {
+  ATRACE_NAME("BufferChannel::HandleImpulse");
+}
+
+bool BufferChannel::HandleMessage(Message& message) {
+  ATRACE_NAME("BufferChannel::HandleMessage");
+  switch (message.GetOp()) {
+    case DetachedBufferRPC::Import::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Import>(
+          *this, &BufferChannel::OnImport, message);
+      return true;
+
+    case DetachedBufferRPC::Duplicate::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Duplicate>(
+          *this, &BufferChannel::OnDuplicate, message);
+      return true;
+
+    case DetachedBufferRPC::Promote::Opcode:
+      DispatchRemoteMethod<DetachedBufferRPC::Promote>(
+          *this, &BufferChannel::OnPromote, message);
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+Status<BufferDescription<BorrowedHandle>> BufferChannel::OnImport(
+    Message& /*message*/) {
+  ATRACE_NAME("BufferChannel::OnImport");
+  ALOGD_IF(TRACE, "BufferChannel::OnImport: buffer=%d.",
+           buffer_id());
+
+  return BufferDescription<BorrowedHandle>{buffer_node_->buffer(),
+                                           buffer_node_->metadata_buffer(),
+                                           buffer_id(),
+                                           channel_id(),
+                                           buffer_state_bit_,
+                                           BorrowedHandle{},
+                                           BorrowedHandle{}};
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnDuplicate(
+    Message& message) {
+  ATRACE_NAME("BufferChannel::OnDuplicate");
+  ALOGD_IF(TRACE, "BufferChannel::OnDuplicate: buffer=%d.",
+           buffer_id());
+
+  int channel_id;
+  auto status = message.PushChannel(0, nullptr, &channel_id);
+  if (!status) {
+    ALOGE(
+        "BufferChannel::OnDuplicate: Failed to push buffer channel: %s",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
+  }
+
+  // Try find the next buffer state bit which has not been claimed by any
+  // other buffers yet.
+  uint64_t buffer_state_bit =
+      BufferHubDefs::FindNextClearedBit(buffer_node_->active_buffer_bit_mask() |
+                                        BufferHubDefs::kProducerStateBit);
+  if (buffer_state_bit == 0ULL) {
+    ALOGE(
+        "BufferChannel::OnDuplicate: reached the maximum mumber of channels "
+        "per buffer node: 63.");
+    return ErrorStatus(E2BIG);
+  }
+
+  auto channel =
+      std::shared_ptr<BufferChannel>(new BufferChannel(
+          service(), buffer_id(), channel_id, buffer_node_, buffer_state_bit));
+  if (!channel) {
+    ALOGE("BufferChannel::OnDuplicate: Invalid buffer.");
+    return ErrorStatus(EINVAL);
+  }
+
+  const auto channel_status =
+      service()->SetChannel(channel_id, std::move(channel));
+  if (!channel_status) {
+    // Technically, this should never fail, as we just pushed the channel. Note
+    // that LOG_FATAL will be stripped out in non-debug build.
+    LOG_FATAL(
+        "BufferChannel::OnDuplicate: Failed to set new buffer channel: %s.",
+        channel_status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
+Status<RemoteChannelHandle> BufferChannel::OnPromote(
+    Message& message) {
+  ATRACE_NAME("BufferChannel::OnPromote");
+  ALOGD_IF(TRACE, "BufferChannel::OnPromote: buffer_id=%d", buffer_id());
+
+  // Check whether this is the channel exclusive owner of the buffer_node_.
+  if (buffer_state_bit_ != buffer_node_->active_buffer_bit_mask()) {
+    ALOGE(
+        "BufferChannel::OnPromote: Cannot promote this BufferChannel as its "
+        "BufferNode is shared between multiple channels. This channel's  state "
+        "bit=0x%" PRIx64 ", acitve_buffer_bit_mask=0x%" PRIx64 ".",
+        buffer_state_bit_, buffer_node_->active_buffer_bit_mask());
+    return ErrorStatus(EINVAL);
+  }
+
+  // Note that the new ProducerChannel will have different channel_id, but
+  // inherits the buffer_id from the DetachedBuffer.
+  int channel_id;
+  auto status = message.PushChannel(0, nullptr, &channel_id);
+  if (!status) {
+    ALOGE(
+        "BufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
+        status.GetErrorMessage().c_str());
+    return ErrorStatus(ENOMEM);
+  }
+
+  IonBuffer buffer = std::move(buffer_node_->buffer());
+  IonBuffer metadata_buffer = std::move(buffer_node_->metadata_buffer());
+  size_t user_metadata_size = buffer_node_->user_metadata_size();
+
+  std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
+      service(), buffer_id(), channel_id, std::move(buffer),
+      std::move(metadata_buffer), user_metadata_size);
+  if (!channel) {
+    ALOGE(
+        "BufferChannel::OnPromote: Failed to create ProducerChannel from a "
+        "BufferChannel, buffer_id=%d.",
+        buffer_id());
+  }
+
+  const auto channel_status =
+      service()->SetChannel(channel_id, std::move(channel));
+  if (!channel_status) {
+    // Technically, this should never fail, as we just pushed the channel. Note
+    // that LOG_FATAL will be stripped out in non-debug build.
+    LOG_FATAL(
+        "BufferChannel::OnPromote: Failed to set new producer buffer channel: "
+        "%s.",
+        channel_status.GetErrorMessage().c_str());
+  }
+
+  return status;
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/bufferhubd/buffer_channel.h b/services/vr/bufferhubd/buffer_channel.h
new file mode 100644
index 0000000..ac99a73
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_channel.h
@@ -0,0 +1,66 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
+
+#include "buffer_hub.h"
+#include "buffer_node.h"
+
+#include <pdx/channel_handle.h>
+#include <pdx/file_handle.h>
+
+namespace android {
+namespace dvr {
+
+class BufferChannel : public BufferHubChannel {
+ public:
+  ~BufferChannel() override;
+
+  template <typename... Args>
+  static std::unique_ptr<BufferChannel> Create(Args&&... args) {
+    auto buffer = std::unique_ptr<BufferChannel>(
+        new BufferChannel(std::forward<Args>(args)...));
+    return buffer->IsValid() ? std::move(buffer) : nullptr;
+  }
+
+  // Returns whether the object holds a valid graphic buffer.
+  bool IsValid() const {
+    return buffer_node_ != nullptr && buffer_node_->IsValid();
+  }
+
+  // Captures buffer info for use by BufferHubService::DumpState().
+  BufferInfo GetBufferInfo() const override;
+
+  bool HandleMessage(pdx::Message& message) override;
+  void HandleImpulse(pdx::Message& message) override;
+
+ private:
+  // Creates a detached buffer from existing IonBuffers.
+  BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+                IonBuffer buffer, IonBuffer metadata_buffer,
+                size_t user_metadata_size);
+
+  // Allocates a new detached buffer.
+  BufferChannel(BufferHubService* service, int buffer_id, uint32_t width,
+                uint32_t height, uint32_t layer_count, uint32_t format,
+                uint64_t usage, size_t user_metadata_size);
+
+  // Creates a detached buffer from an existing BufferNode.
+  BufferChannel(BufferHubService* service, int buffer_id, int channel_id,
+                std::shared_ptr<BufferNode> buffer_node,
+                uint64_t buffer_state_bit);
+
+  pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
+      pdx::Message& message);
+  pdx::Status<pdx::RemoteChannelHandle> OnDuplicate(pdx::Message& message);
+  pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
+
+  // The concrete implementation of the Buffer object.
+  std::shared_ptr<BufferNode> buffer_node_;
+
+  // The state bit of this buffer. Must be one the lower 63 bits.
+  uint64_t buffer_state_bit_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFERHUBD_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/buffer_hub.cpp b/services/vr/bufferhubd/buffer_hub.cpp
index e57c8ed..c0ee31b 100644
--- a/services/vr/bufferhubd/buffer_hub.cpp
+++ b/services/vr/bufferhubd/buffer_hub.cpp
@@ -13,8 +13,8 @@
 
 #include <pdx/default_transport/service_endpoint.h>
 #include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
 #include "consumer_channel.h"
-#include "detached_buffer_channel.h"
 #include "producer_channel.h"
 #include "producer_queue_channel.h"
 
@@ -267,7 +267,7 @@
       return {};
 
     case DetachedBufferRPC::Promote::Opcode:
-      // In addition to the message handler in the DetachedBufferChannel's
+      // In addition to the message handler in the BufferChannel's
       // HandleMessage method, we also need to invalid the channel. Note that
       // this has to be done after HandleMessage returns to make sure the IPC
       // request has went back to the client first.
@@ -332,9 +332,9 @@
     return ErrorStatus(EALREADY);
   }
 
-  std::unique_ptr<DetachedBufferChannel> channel =
-      DetachedBufferChannel::Create(this, buffer_id, width, height, layer_count,
-                                    format, usage, user_metadata_size);
+  std::unique_ptr<BufferChannel> channel =
+      BufferChannel::Create(this, buffer_id, width, height, layer_count, format,
+                            usage, user_metadata_size);
   if (!channel) {
     ALOGE(
         "BufferHubService::OnCreateDetachedBuffer: Failed to allocate buffer, "
diff --git a/services/vr/bufferhubd/buffer_node.cpp b/services/vr/bufferhubd/buffer_node.cpp
new file mode 100644
index 0000000..de22bba
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.cpp
@@ -0,0 +1,53 @@
+#include "buffer_node.h"
+
+#include <private/dvr/buffer_hub_defs.h>
+
+namespace android {
+namespace dvr {
+
+BufferNode::BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+                       size_t user_metadata_size)
+    : buffer_(std::move(buffer)),
+      metadata_buffer_(std::move(metadata_buffer)),
+      user_metadata_size_(user_metadata_size) {}
+
+// Allocates a new BufferNode.
+BufferNode::BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+                       uint32_t format, uint64_t usage,
+                       size_t user_metadata_size)
+    : user_metadata_size_(user_metadata_size) {
+  // The size the of metadata buffer is used as the "width" parameter during
+  // allocation. Thus it cannot overflow uint32_t.
+  if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
+                              BufferHubDefs::kMetadataHeaderSize)) {
+    ALOGE(
+        "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
+    return;
+  }
+
+  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
+    ALOGE(
+        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+        "buffer: %s",
+        strerror(-ret));
+    return;
+  }
+
+  // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
+  // user requested metadata.
+  const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
+  if (int ret = metadata_buffer_.Alloc(size,
+                                       /*height=*/1,
+                                       /*layer_count=*/1,
+                                       BufferHubDefs::kMetadataFormat,
+                                       BufferHubDefs::kMetadataUsage)) {
+    ALOGE(
+        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
+        "metadata: %s",
+        strerror(-ret));
+    return;
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/services/vr/bufferhubd/buffer_node.h b/services/vr/bufferhubd/buffer_node.h
new file mode 100644
index 0000000..4bcf4e3
--- /dev/null
+++ b/services/vr/bufferhubd/buffer_node.h
@@ -0,0 +1,55 @@
+#ifndef ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+#define ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
+
+#include <private/dvr/ion_buffer.h>
+
+namespace android {
+namespace dvr {
+
+class BufferNode {
+ public:
+  // Creates a BufferNode from existing IonBuffers, i.e. creating from an
+  // existing ProducerChannel.
+  BufferNode(IonBuffer buffer, IonBuffer metadata_buffer,
+             size_t user_metadata_size);
+
+  // Allocates a new BufferNode.
+  BufferNode(uint32_t width, uint32_t height, uint32_t layer_count,
+             uint32_t format, uint64_t usage, size_t user_metadata_size);
+
+  // Returns whether the object holds a valid graphic buffer.
+  bool IsValid() const {
+    return buffer_.IsValid() && metadata_buffer_.IsValid();
+  }
+
+  size_t user_metadata_size() const { return user_metadata_size_; }
+  uint64_t active_buffer_bit_mask() const { return active_buffer_bit_mask_; }
+  void set_buffer_state_bit(uint64_t buffer_state_bit) {
+    active_buffer_bit_mask_ |= buffer_state_bit;
+  }
+
+  // Used to take out IonBuffers.
+  IonBuffer& buffer() { return buffer_; }
+  IonBuffer& metadata_buffer() { return metadata_buffer_; }
+
+  // Used to access IonBuffers.
+  const IonBuffer& buffer() const { return buffer_; }
+  const IonBuffer& metadata_buffer() const { return metadata_buffer_; }
+
+ private:
+  // Gralloc buffer handles.
+  IonBuffer buffer_;
+  IonBuffer metadata_buffer_;
+
+  // Size of user requested metadata.
+  const size_t user_metadata_size_;
+
+  // All active buffer bits. Valid bits are the lower 63 bits, while the
+  // highest bit is reserved for the exclusive writing and should not be set.
+  uint64_t active_buffer_bit_mask_ = 0ULL;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_BUFFERHUBD_BUFFER_NODE_H_
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
deleted file mode 100644
index 3061805..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ /dev/null
@@ -1,160 +0,0 @@
-#include "detached_buffer_channel.h"
-#include "producer_channel.h"
-
-using android::pdx::BorrowedHandle;
-using android::pdx::ErrorStatus;
-using android::pdx::Message;
-using android::pdx::RemoteChannelHandle;
-using android::pdx::Status;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
-                                             int buffer_id, int channel_id,
-                                             IonBuffer buffer,
-                                             IonBuffer metadata_buffer,
-                                             size_t user_metadata_size)
-    : BufferHubChannel(service, buffer_id, channel_id, kDetachedBufferType),
-      buffer_(std::move(buffer)),
-      metadata_buffer_(std::move(metadata_buffer)),
-      user_metadata_size_(user_metadata_size) {
-}
-
-DetachedBufferChannel::DetachedBufferChannel(BufferHubService* service,
-                                             int buffer_id, uint32_t width,
-                                             uint32_t height,
-                                             uint32_t layer_count,
-                                             uint32_t format, uint64_t usage,
-                                             size_t user_metadata_size)
-    : BufferHubChannel(service, buffer_id, buffer_id, kDetachedBufferType),
-      user_metadata_size_(user_metadata_size) {
-  // The size the of metadata buffer is used as the "width" parameter during
-  // allocation. Thus it cannot overflow uint32_t.
-  if (user_metadata_size_ >= (std::numeric_limits<uint32_t>::max() -
-                              BufferHubDefs::kMetadataHeaderSize)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: metadata size too big.");
-    return;
-  }
-
-  if (int ret = buffer_.Alloc(width, height, layer_count, format, usage)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
-        "buffer: %s",
-        strerror(-ret));
-    return;
-  }
-
-  // Buffer metadata has two parts: 1) a fixed sized metadata header; and 2)
-  // user requested metadata.
-  const size_t size = BufferHubDefs::kMetadataHeaderSize + user_metadata_size_;
-  if (int ret = metadata_buffer_.Alloc(size,
-                                       /*height=*/1,
-                                       /*layer_count=*/1,
-                                       BufferHubDefs::kMetadataFormat,
-                                       BufferHubDefs::kMetadataUsage)) {
-    ALOGE(
-        "DetachedBufferChannel::DetachedBufferChannel: Failed to allocate "
-        "metadata: %s",
-        strerror(-ret));
-    return;
-  }
-}
-
-DetachedBufferChannel::~DetachedBufferChannel() {
-  ALOGD_IF(TRACE,
-           "DetachedBufferChannel::~DetachedBufferChannel: channel_id=%d "
-           "buffer_id=%d.",
-           channel_id(), buffer_id());
-  Hangup();
-}
-
-BufferHubChannel::BufferInfo DetachedBufferChannel::GetBufferInfo() const {
-  return BufferInfo(buffer_id(), /*consumer_count=*/0, buffer_.width(),
-                    buffer_.height(), buffer_.layer_count(), buffer_.format(),
-                    buffer_.usage(), /*pending_count=*/0, /*state=*/0,
-                    /*signaled_mask=*/0, /*index=*/0);
-}
-
-void DetachedBufferChannel::HandleImpulse(Message& /*message*/) {
-  ATRACE_NAME("DetachedBufferChannel::HandleImpulse");
-}
-
-bool DetachedBufferChannel::HandleMessage(Message& message) {
-  ATRACE_NAME("DetachedBufferChannel::HandleMessage");
-  switch (message.GetOp()) {
-    case DetachedBufferRPC::Import::Opcode:
-      DispatchRemoteMethod<DetachedBufferRPC::Import>(
-          *this, &DetachedBufferChannel::OnImport, message);
-      return true;
-
-    case DetachedBufferRPC::Promote::Opcode:
-      DispatchRemoteMethod<DetachedBufferRPC::Promote>(
-          *this, &DetachedBufferChannel::OnPromote, message);
-      return true;
-
-    default:
-      return false;
-  }
-}
-
-Status<BufferDescription<BorrowedHandle>> DetachedBufferChannel::OnImport(
-    Message& /*message*/) {
-  ATRACE_NAME("DetachedBufferChannel::OnGetBuffer");
-  ALOGD_IF(TRACE, "DetachedBufferChannel::OnGetBuffer: buffer=%d.",
-           buffer_id());
-
-  return BufferDescription<BorrowedHandle>{buffer_,
-                                           metadata_buffer_,
-                                           buffer_id(),
-                                           channel_id(),
-                                           /*buffer_state_bit=*/0,
-                                           BorrowedHandle{},
-                                           BorrowedHandle{}};
-}
-
-Status<RemoteChannelHandle> DetachedBufferChannel::OnPromote(
-    Message& message) {
-  ATRACE_NAME("DetachedBufferChannel::OnPromote");
-  ALOGD_IF(TRACE, "DetachedBufferChannel::OnPromote: buffer_id=%d",
-           buffer_id());
-
-  // Note that the new ProducerChannel will have different channel_id, but
-  // inherits the buffer_id from the DetachedBuffer.
-  int channel_id;
-  auto status = message.PushChannel(0, nullptr, &channel_id);
-  if (!status) {
-    ALOGE(
-        "DetachedBufferChannel::OnPromote: Failed to push ProducerChannel: %s.",
-        status.GetErrorMessage().c_str());
-    return ErrorStatus(ENOMEM);
-  }
-
-  std::unique_ptr<ProducerChannel> channel = ProducerChannel::Create(
-      service(), buffer_id(), channel_id, std::move(buffer_),
-      std::move(metadata_buffer_), user_metadata_size_);
-  if (!channel) {
-    ALOGE(
-        "DetachedBufferChannel::OnPromote: Failed to create ProducerChannel "
-        "from a DetachedBufferChannel, buffer_id=%d.",
-        buffer_id());
-  }
-
-  const auto channel_status =
-      service()->SetChannel(channel_id, std::move(channel));
-  if (!channel_status) {
-    // Technically, this should never fail, as we just pushed the channel. Note
-    // that LOG_FATAL will be stripped out in non-debug build.
-    LOG_FATAL(
-        "DetachedBufferChannel::OnPromote: Failed to set new producer buffer "
-        "channel: %s.",
-        channel_status.GetErrorMessage().c_str());
-  }
-
-  return status;
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/services/vr/bufferhubd/detached_buffer_channel.h b/services/vr/bufferhubd/detached_buffer_channel.h
deleted file mode 100644
index 8b6dab8..0000000
--- a/services/vr/bufferhubd/detached_buffer_channel.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-#define ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
-
-#include "buffer_hub.h"
-
-#include <pdx/channel_handle.h>
-#include <pdx/file_handle.h>
-
-namespace android {
-namespace dvr {
-
-class DetachedBufferChannel : public BufferHubChannel {
- public:
-  ~DetachedBufferChannel() override;
-
-  template <typename... Args>
-  static std::unique_ptr<DetachedBufferChannel> Create(Args&&... args) {
-    auto buffer = std::unique_ptr<DetachedBufferChannel>(
-        new DetachedBufferChannel(std::forward<Args>(args)...));
-    return buffer->IsValid() ? std::move(buffer) : nullptr;
-  }
-
-  // Returns whether the object holds a valid graphic buffer.
-  bool IsValid() const {
-    return buffer_.IsValid() && metadata_buffer_.IsValid();
-  }
-
-  size_t user_metadata_size() const { return user_metadata_size_; }
-
-  // Captures buffer info for use by BufferHubService::DumpState().
-  BufferInfo GetBufferInfo() const override;
-
-  bool HandleMessage(pdx::Message& message) override;
-  void HandleImpulse(pdx::Message& message) override;
-
- private:
-  // Creates a detached buffer from existing IonBuffers.
-  DetachedBufferChannel(BufferHubService* service, int buffer_id,
-                        int channel_id, IonBuffer buffer,
-                        IonBuffer metadata_buffer, size_t user_metadata_size);
-
-  // Allocates a new detached buffer.
-  DetachedBufferChannel(BufferHubService* service, int buffer_id,
-                        uint32_t width, uint32_t height, uint32_t layer_count,
-                        uint32_t format, uint64_t usage,
-                        size_t user_metadata_size);
-
-  pdx::Status<BufferDescription<pdx::BorrowedHandle>> OnImport(
-      pdx::Message& message);
-  pdx::Status<pdx::RemoteChannelHandle> OnPromote(pdx::Message& message);
-
-  // Gralloc buffer handles.
-  IonBuffer buffer_;
-  IonBuffer metadata_buffer_;
-
-  // Size of user requested metadata.
-  const size_t user_metadata_size_;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_BUFFERHUBD_DETACHED_BUFFER_CHANNEL_H_
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index 97af660..19d48f2 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -12,8 +12,8 @@
 #include <thread>
 
 #include <private/dvr/bufferhub_rpc.h>
+#include "buffer_channel.h"
 #include "consumer_channel.h"
-#include "detached_buffer_channel.h"
 
 using android::pdx::BorrowedHandle;
 using android::pdx::ErrorStatus;
@@ -27,14 +27,6 @@
 namespace android {
 namespace dvr {
 
-namespace {
-
-static inline uint64_t FindNextClearedBit(uint64_t bits) {
-  return ~bits - (~bits & (~bits - 1));
-}
-
-}  // namespace
-
 ProducerChannel::ProducerChannel(BufferHubService* service, int buffer_id,
                                  int channel_id, IonBuffer buffer,
                                  IonBuffer metadata_buffer,
@@ -270,7 +262,7 @@
 
   // Try find the next consumer state bit which has not been claimed by any
   // consumer yet.
-  uint64_t consumer_state_bit = FindNextClearedBit(
+  uint64_t consumer_state_bit = BufferHubDefs::FindNextClearedBit(
       active_consumer_bit_mask_ | orphaned_consumer_bit_mask_ |
       BufferHubDefs::kProducerStateBit);
   if (consumer_state_bit == 0ULL) {
@@ -419,10 +411,9 @@
     return ErrorStatus(-ret);
   };
 
-  std::unique_ptr<DetachedBufferChannel> channel =
-      DetachedBufferChannel::Create(
-          service(), buffer_id(), channel_id, std::move(buffer_),
-          std::move(metadata_buffer_), user_metadata_size_);
+  std::unique_ptr<BufferChannel> channel = BufferChannel::Create(
+      service(), buffer_id(), channel_id, std::move(buffer_),
+      std::move(metadata_buffer_), user_metadata_size_);
   if (!channel) {
     ALOGE("ProducerChannel::OnProducerDetach: Invalid buffer.");
     return ErrorStatus(EINVAL);
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index e36b7bc..76eca35 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 1
-define VERSION_PATCH 80
+define VERSION_PATCH 82
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -533,6 +533,10 @@
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned"
 
+// 207
+@extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2
+@extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints"
+
 /////////////
 //  Types  //
 /////////////
@@ -1663,6 +1667,10 @@
     //@extension("VK_EXT_vertex_attribute_divisor") // 191
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT   = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT       = 1000190001,
+
+    //@extension("VK_NV_device_diagnostic_checkpoints") // 207
+    VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV                        = 1000206000,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV     = 1000206001,
 }
 
 enum VkSubpassContents {
@@ -5335,7 +5343,7 @@
     VkStructureType                             sType
     const void*                                 pNext
     u32                                         disabledValidationCheckCount
-    VkValidationCheckEXT*                       pDisabledValidationChecks
+    const VkValidationCheckEXT*                 pDisabledValidationChecks
 }
 
 @extension("VK_NN_vi_surface") // 63
@@ -6788,6 +6796,21 @@
     const VkVertexInputBindingDivisorDescriptionEXT*    pVertexBindingDivisors
 }
 
+@extension("VK_NV_device_diagnostic_checkpoints") // 207
+class VkQueueFamilyCheckpointPropertiesNV {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkPipelineStageFlags                            checkpointExecutionStageMask
+}
+
+@extension("VK_NV_device_diagnostic_checkpoints") // 207
+class VkCheckpointDataNV {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkPipelineStageFlagBits                         stage
+    void*                                           pCheckpointMarker
+}
+
 
 ////////////////
 //  Commands  //
@@ -10584,6 +10607,20 @@
         u32                                         marker) {
 }
 
+@extension("VK_NV_device_diagnostic_checkpoints") // 207
+cmd void vkCmdSetCheckpointNV(
+        VkCommandBuffer                             commandBuffer,
+        const void*                                 pCheckpointMarker) {
+}
+
+@extension("VK_NV_device_diagnostic_checkpoints") // 207
+cmd void vkGetQueueCheckpointDataNV(
+        VkQueue                                     queue,
+        u32*                                        pCheckpointDataCount,
+        VkCheckpointDataNV*                         pCheckpointData) {
+}
+
+
 ////////////////
 // Validation //
 ////////////////
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index 06c8607..d511015 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,7 +43,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 80
+#define VK_HEADER_VERSION 82
 
 
 #define VK_NULL_HANDLE 0
@@ -406,6 +406,8 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
+    VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000,
+    VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001,
     VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES,
@@ -6411,10 +6413,10 @@
 } VkValidationCheckEXT;
 
 typedef struct VkValidationFlagsEXT {
-    VkStructureType          sType;
-    const void*              pNext;
-    uint32_t                 disabledValidationCheckCount;
-    VkValidationCheckEXT*    pDisabledValidationChecks;
+    VkStructureType                sType;
+    const void*                    pNext;
+    uint32_t                       disabledValidationCheckCount;
+    const VkValidationCheckEXT*    pDisabledValidationChecks;
 } VkValidationFlagsEXT;
 
 
@@ -7732,7 +7734,7 @@
 
 
 #define VK_EXT_vertex_attribute_divisor 1
-#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 1
+#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
 
 typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
@@ -7760,6 +7762,38 @@
 #define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned"
 
 
+#define VK_NV_device_diagnostic_checkpoints 1
+#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2
+#define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints"
+
+typedef struct VkQueueFamilyCheckpointPropertiesNV {
+    VkStructureType         sType;
+    void*                   pNext;
+    VkPipelineStageFlags    checkpointExecutionStageMask;
+} VkQueueFamilyCheckpointPropertiesNV;
+
+typedef struct VkCheckpointDataNV {
+    VkStructureType            sType;
+    void*                      pNext;
+    VkPipelineStageFlagBits    stage;
+    void*                      pCheckpointMarker;
+} VkCheckpointDataNV;
+
+
+typedef void (VKAPI_PTR *PFN_vkCmdSetCheckpointNV)(VkCommandBuffer commandBuffer, const void* pCheckpointMarker);
+typedef void (VKAPI_PTR *PFN_vkGetQueueCheckpointDataNV)(VkQueue queue, uint32_t* pCheckpointDataCount, VkCheckpointDataNV* pCheckpointData);
+
+#ifndef VK_NO_PROTOTYPES
+VKAPI_ATTR void VKAPI_CALL vkCmdSetCheckpointNV(
+    VkCommandBuffer                             commandBuffer,
+    const void*                                 pCheckpointMarker);
+
+VKAPI_ATTR void VKAPI_CALL vkGetQueueCheckpointDataNV(
+    VkQueue                                     queue,
+    uint32_t*                                   pCheckpointDataCount,
+    VkCheckpointDataNV*                         pCheckpointData);
+#endif
+
 #ifdef __cplusplus
 }
 #endif