blast: BufferStateLayer

Adds the initial foundation for supporting buffers on
transactions as well as the other metadata that had been passed
over BufferQueue.

Bug: 80477568
Test: Transaction_test.cpp
Change-Id: I61e44462c66c1a912adbabf62015e66bde44c216
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 0be1fd7..3fa1311 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -92,6 +92,7 @@
         "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 6484245..e724666 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -136,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;
@@ -232,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());
 
@@ -518,7 +518,7 @@
 
     // FIXME: postedRegion should be dirty & bounds
     // transform the dirty region to window-manager space
-    return getTransform().transform(Region(Rect(s.active_legacy.w, s.active_legacy.h)));
+    return getTransform().transform(Region(Rect(getActiveWidth(s), getActiveHeight(s))));
 }
 
 // transaction
@@ -641,9 +641,10 @@
 
     Transform t = getTransform();
     Rect win = bounds;
-    if (!s.finalCrop_legacy.isEmpty()) {
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
         win = t.transform(win);
-        if (!win.intersect(s.finalCrop_legacy, &win)) {
+        if (!win.intersect(finalCrop, &win)) {
             win.clear();
         }
         win = t.inverse().transform(win);
@@ -652,10 +653,10 @@
         }
     }
 
-    float left = float(win.left) / float(s.active_legacy.w);
-    float top = float(win.top) / float(s.active_legacy.h);
-    float right = float(win.right) / float(s.active_legacy.w);
-    float bottom = float(win.bottom) / float(s.active_legacy.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
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 6ffcff4..13f4e83 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -78,8 +78,8 @@
 
     // onDraw - draws the surface.
     void onDraw(const RenderArea& renderArea, const Region& clip,
-                bool useIdentityTransform) const override;
-    void drawNow(const RenderArea& renderArea, bool useIdentityTransform) const;
+                bool useIdentityTransform) override;
+    void drawNow(const RenderArea& renderArea, bool useIdentityTransform);
 
     bool isHdrY410() const override;
 
@@ -102,7 +102,6 @@
 
     bool hasReadyFrame() const override;
 
-private:
     // Returns the current scaling mode, unless mOverrideScalingMode
     // is set, in which case, it returns mOverrideScalingMode
     uint32_t getEffectiveScalingMode() const override;
@@ -117,7 +116,7 @@
     virtual nsecs_t getDesiredPresentTime() = 0;
     virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
 
-    virtual void getDrawingTransformMatrix(float matrix[16]) 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;
@@ -136,7 +135,7 @@
 
     virtual bool hasDrawingBuffer() const = 0;
 
-    virtual void setFilteringEnabled(bool enabled) const = 0;
+    virtual void setFilteringEnabled(bool enabled) = 0;
 
     virtual status_t bindTextureImage() const = 0;
     virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 1bf9cf2..0913de4 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -152,7 +152,7 @@
     return mConsumer->getCurrentFenceTime();
 }
 
-void BufferQueueLayer::getDrawingTransformMatrix(float matrix[16]) const {
+void BufferQueueLayer::getDrawingTransformMatrix(float *matrix) {
     return mConsumer->getTransformMatrix(matrix);
 }
 
@@ -228,7 +228,7 @@
     return mQueuedFrames > 0;
 }
 
-void BufferQueueLayer::setFilteringEnabled(bool enabled) const {
+void BufferQueueLayer::setFilteringEnabled(bool enabled) {
     return mConsumer->setFilteringEnabled(enabled);
 }
 
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 7454e20..579ed81 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -68,7 +68,7 @@
     nsecs_t getDesiredPresentTime() override;
     std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
 
-    void getDrawingTransformMatrix(float matrix[16]) const override;
+    void getDrawingTransformMatrix(float *matrix) override;
     uint32_t getDrawingTransform() const override;
     ui::Dataspace getDrawingDataSpace() const override;
     Rect getDrawingCrop() const override;
@@ -87,7 +87,7 @@
 
     bool hasDrawingBuffer() const override;
 
-    void setFilteringEnabled(bool enabled) const override;
+    void setFilteringEnabled(bool enabled) override;
 
     status_t bindTextureImage() const override;
     status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
new file mode 100644
index 0000000..2e411f1
--- /dev/null
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -0,0 +1,545 @@
+/*
+ * 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() {
+    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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index eeee0ae..ee9ee78 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -114,6 +114,17 @@
     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;
@@ -293,17 +304,19 @@
 
 Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
     const Layer::State& s(getDrawingState());
-    Rect win(s.active_legacy.w, s.active_legacy.h);
+    Rect win(getActiveWidth(s), getActiveHeight(s));
 
-    if (!s.crop_legacy.isEmpty()) {
-        win.intersect(s.crop_legacy, &win);
+    Rect crop = getCrop(s);
+    if (!crop.isEmpty()) {
+        win.intersect(crop, &win);
     }
 
     Transform t = getTransform();
     win = t.transform(win);
 
-    if (!s.finalCrop_legacy.isEmpty()) {
-        win.intersect(s.finalCrop_legacy, &win);
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        win.intersect(finalCrop, &win);
     }
 
     const sp<Layer>& p = mDrawingParent.promote();
@@ -322,7 +335,7 @@
     }
 
     if (reduceTransparentRegion) {
-        auto const screenTransparentRegion = t.transform(s.activeTransparentRegion_legacy);
+        auto const screenTransparentRegion = t.transform(getActiveTransparentRegion(s));
         win = reduce(win, screenTransparentRegion);
     }
 
@@ -331,15 +344,16 @@
 
 FloatRect Layer::computeBounds() const {
     const Layer::State& s(getDrawingState());
-    return computeBounds(s.activeTransparentRegion_legacy);
+    return computeBounds(getActiveTransparentRegion(s));
 }
 
 FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
     const Layer::State& s(getDrawingState());
-    Rect win(s.active_legacy.w, s.active_legacy.h);
+    Rect win(getActiveWidth(s), getActiveHeight(s));
 
-    if (!s.crop_legacy.isEmpty()) {
-        win.intersect(s.crop_legacy, &win);
+    Rect crop = getCrop(s);
+    if (!crop.isEmpty()) {
+        win.intersect(crop, &win);
     }
 
     const auto& p = mDrawingParent.promote();
@@ -379,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_legacy.w, s.active_legacy.h);
-    if (!s.crop_legacy.isEmpty()) {
-        activeCrop.intersect(s.crop_legacy, &activeCrop);
+    Rect activeCrop(getActiveWidth(s), getActiveHeight(s));
+    Rect crop = getCrop(s);
+    if (!crop.isEmpty()) {
+        activeCrop.intersect(crop, &activeCrop);
     }
 
     Transform t = getTransform();
@@ -389,8 +404,9 @@
     if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
         activeCrop.clear();
     }
-    if (!s.finalCrop_legacy.isEmpty()) {
-        if (!activeCrop.intersect(s.finalCrop_legacy, &activeCrop)) {
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        if (!activeCrop.intersect(finalCrop, &activeCrop)) {
             activeCrop.clear();
         }
     }
@@ -424,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_legacy.w, s.active_legacy.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_legacy);
+    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
@@ -449,8 +465,8 @@
         invTransform = (Transform(invTransformOrient) * Transform(invTransform)).getOrientation();
     }
 
-    int winWidth = s.active_legacy.w;
-    int winHeight = s.active_legacy.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
@@ -462,10 +478,10 @@
         if (is_h_flipped == is_v_flipped) {
             invTransform ^= NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_FLIP_H;
         }
-        winWidth = s.active_legacy.h;
-        winHeight = s.active_legacy.w;
+        winWidth = getActiveHeight(s);
+        winHeight = getActiveWidth(s);
     }
-    const Rect winCrop = activeCrop.transform(invTransform, s.active_legacy.w, s.active_legacy.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);
@@ -518,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_legacy);
+    Region activeTransparentRegion(getActiveTransparentRegion(s));
     Transform t = getTransform();
-    if (!s.crop_legacy.isEmpty()) {
-        Rect activeCrop(s.crop_legacy);
+    Rect activeCrop = getCrop(s);
+    if (!activeCrop.isEmpty()) {
         activeCrop = t.transform(activeCrop);
         if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
             activeCrop.clear();
@@ -533,23 +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_legacy.w, s.active_legacy.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_legacy.w, activeCrop.top));
+        activeTransparentRegion.orSelf(Rect(0, 0, getActiveWidth(s), activeCrop.top));
         activeTransparentRegion.orSelf(
-                Rect(0, activeCrop.bottom, s.active_legacy.w, s.active_legacy.h));
+                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_legacy.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_legacy.isEmpty()) {
-        if (!frame.intersect(s.finalCrop_legacy, &frame)) {
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        if (!frame.intersect(finalCrop, &frame)) {
             frame.clear();
         }
     }
@@ -682,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_legacy.w, s.active_legacy.h);
-    if (!s.crop_legacy.isEmpty()) {
-        win.intersect(s.crop_legacy, &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_legacy);
+    Rect bounds = reduce(win, getActiveTransparentRegion(s));
     Rect frame(getTransform().transform(bounds));
     frame.intersect(display->getViewport(), &frame);
-    if (!s.finalCrop_legacy.isEmpty()) {
-        frame.intersect(s.finalCrop_legacy, &frame);
+    Rect finalCrop = getFinalCrop(s);
+    if (!finalCrop.isEmpty()) {
+        frame.intersect(finalCrop, &frame);
     }
     auto& displayTransform = display->getTransform();
     auto position = displayTransform.transform(frame);
@@ -709,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);
 }
 
@@ -844,11 +863,12 @@
         rt = layerTransform.transform(rt);
     }
 
-    if (!s.finalCrop_legacy.isEmpty()) {
-        boundPoint(&lt, s.finalCrop_legacy);
-        boundPoint(&lb, s.finalCrop_legacy);
-        boundPoint(&rb, s.finalCrop_legacy);
-        boundPoint(&rt, s.finalCrop_legacy);
+    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>());
@@ -984,19 +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_legacy.w != s.requested_legacy.w) ||
-            (c.requested_legacy.h != s.requested_legacy.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
@@ -1007,16 +1019,18 @@
                  "  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_legacy.w, c.active_legacy.h, c.crop_legacy.left, c.crop_legacy.top,
-                 c.crop_legacy.right, c.crop_legacy.bottom, c.crop_legacy.getWidth(),
-                 c.crop_legacy.getHeight(), c.requested_legacy.w, c.requested_legacy.h,
+                 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_legacy.w, c.requested_legacy.h);
+        setDefaultBufferSize(stateToCommit->requested_legacy.w, stateToCommit->requested_legacy.h);
     }
 
     // Don't let Layer::doTransaction update the drawing state
@@ -1037,8 +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_legacy.w != c.active_legacy.w) ||
-                                (c.requested_legacy.h != c.active_legacy.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) {
@@ -1062,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_legacy.transform.tx();
-            float ty = c.active_legacy.transform.ty();
-            c.active_legacy = c.requested_legacy;
-            c.active_legacy.transform.set(tx, ty);
-            editCurrentState.active_legacy = c.active_legacy;
+            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_legacy = editCurrentState.requested_legacy;
-            c.active_legacy = c.requested_legacy;
+            stateToCommit->active_legacy = stateToCommit->requested_legacy;
         }
     }
 
-    if (s.active_legacy != c.active_legacy) {
+    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;
     }
@@ -1087,9 +1118,8 @@
         this->contentDirty = true;
 
         // we may use linear filtering, if the matrix scales us
-        const uint8_t type = c.active_legacy.transform.getType();
-        mNeedsFiltering =
-                (!c.active_legacy.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
@@ -1278,6 +1308,7 @@
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
+
 bool Layer::setTransparentRegionHint(const Region& transparent) {
     mCurrentState.requestedTransparentRegion_legacy = transparent;
     mCurrentState.modified = true;
@@ -1415,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();
@@ -1889,14 +1921,14 @@
                 bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth();
                 bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight();
             }
-            float sx = p->getDrawingState().active_legacy.w / static_cast<float>(bufferWidth);
-            float sy = p->getDrawingState().active_legacy.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_legacy.transform;
+    return t * getActiveTransform(getDrawingState());
 }
 
 half Layer::getAlpha() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 96ec84b..a48cdff 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -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_legacy(const Rect& crop, bool immediate);
+    virtual bool setCrop_legacy(const Rect& crop, bool immediate);
     // Parent buffer space/display space
-    bool setFinalCrop_legacy(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_legacy(const sp<IBinder>& barrierHandle, uint64_t frameNumber);
-    void deferTransactionUntil_legacy(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
@@ -536,7 +580,7 @@
     // SurfaceFlinger to complete a transaction.
     void commitChildList();
     int32_t getZ() const;
-    void pushPendingState();
+    virtual void pushPendingState();
 
 protected:
     // constant
@@ -620,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();
 
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index 8b37170..b5aceba 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -78,6 +78,7 @@
     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 fd0ca82..70558d4 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -101,7 +101,8 @@
 
         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_legacy={ wh={%4u,%4u} }}\n",
                  mName, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 64f1eaf..399fbd8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -64,6 +64,7 @@
 
 #include "BufferLayer.h"
 #include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
 #include "Client.h"
 #include "ColorLayer.h"
 #include "Colorizer.h"
@@ -2766,7 +2767,7 @@
                 if (translucent) {
                     if (tr.preserveRects()) {
                         // transform the transparent region
-                        transparentRegion = tr.transform(s.activeTransparentRegion_legacy);
+                        transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
                     } else {
                         // transformation too complex, can't do the
                         // transparent region optimization.
@@ -3551,6 +3552,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;
 }
 
@@ -3593,11 +3625,14 @@
     String8 uniqueName = getUniqueLayerName(name);
 
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
-        case ISurfaceComposerClient::eFXSurfaceNormal:
+        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,
@@ -3687,6 +3722,16 @@
     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)
@@ -4864,10 +4909,12 @@
         const Transform& getTransform() const override { return mTransform; }
         Rect getBounds() const override {
             const Layer::State& layerState(mLayer->getDrawingState());
-            return Rect(layerState.active_legacy.w, layerState.active_legacy.h);
+            return Rect(mLayer->getActiveWidth(layerState), mLayer->getActiveHeight(layerState));
         }
-        int getHeight() const override { return mLayer->getDrawingState().active_legacy.h; }
-        int getWidth() const override { return mLayer->getDrawingState().active_legacy.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 {
@@ -4935,12 +4982,12 @@
     Rect crop(sourceCrop);
     if (sourceCrop.width() <= 0) {
         crop.left = 0;
-        crop.right = parent->getCurrentState().active_legacy.w;
+        crop.right = parent->getActiveWidth(parent->getCurrentState());
     }
 
     if (sourceCrop.height() <= 0) {
         crop.top = 0;
-        crop.bottom = parent->getCurrentState().active_legacy.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 a750636..eaaf742 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -356,6 +356,7 @@
     friend class Layer;
     friend class BufferLayer;
     friend class BufferQueueLayer;
+    friend class BufferStateLayer;
     friend class MonitoredProducer;
 
     // For unit tests
@@ -535,6 +536,10 @@
                                     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,
             sp<Layer>* outLayer);
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index c42213a..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;
 
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 2ce32b5..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,10 @@
     }
 }
 
-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();
@@ -1194,10 +1434,23 @@
     shot->expectBorder(crop, Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropEmpty) {
+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();
+    auto shot = screenshot();
+    shot->expectColor(crop, Color::RED);
+    shot->expectBorder(crop, Color::BLACK);
+}
+
+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");
@@ -1212,10 +1465,29 @@
     }
 }
 
-TEST_F(LayerTransactionTest, SetCropOutOfBounds) {
+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");
+        Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    {
+        SCOPED_TRACE("negative rect");
+        Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
+        screenshot()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+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();
@@ -1223,10 +1495,22 @@
     shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropWithTranslation) {
+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();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+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);
@@ -1236,10 +1520,24 @@
     shot->expectBorder(crop + position, Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropWithScale) {
+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);
+    Transaction().setPosition(layer, position.x, position.y).setCrop(layer, crop).apply();
+    auto shot = screenshot();
+    shot->expectColor(crop + position, Color::RED);
+    shot->expectBorder(crop + position, Color::BLACK);
+}
+
+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()
@@ -1251,10 +1549,26 @@
     shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
 }
 
-TEST_F(LayerTransactionTest, SetCropWithResize) {
+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()
+            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+            .setCrop(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, 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_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();
@@ -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,10 +1588,34 @@
     }
 }
 
-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_legacy to be applied with the next resize
     Transaction()
@@ -1302,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();
@@ -1311,10 +1649,45 @@
     }
 }
 
-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_legacy is not immediate even with SCALE_TO_WINDOW override
     Transaction()
@@ -1332,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");
@@ -1342,10 +1715,41 @@
     }
 }
 
-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
@@ -1355,10 +1759,10 @@
     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
     {
@@ -1374,10 +1778,10 @@
     }
 }
 
-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_legacy(layer, Rect(-128, -64, 128, 64)).apply();
@@ -1386,10 +1790,10 @@
     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_legacy(layer, Rect(8, 8, 24, 24)).apply();
@@ -1398,10 +1802,10 @@
     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()
@@ -1413,10 +1817,10 @@
     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_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
@@ -1427,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();
@@ -1436,10 +1840,10 @@
     }
 }
 
-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()
@@ -1464,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();
@@ -1473,10 +1877,10 @@
     }
 }
 
-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()
@@ -1494,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");
@@ -1504,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() {
@@ -2569,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)
@@ -2603,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)
@@ -2636,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);
@@ -2655,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");