Merge "Add buffer rejection logic to BlastBufferQueue"
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index ba72f9b..cce434a 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -166,8 +166,8 @@
                                            const std::vector<SurfaceControlStats>& stats) {
     std::unique_lock _lock{mMutex};
     ATRACE_CALL();
-
     BQA_LOGV("transactionCallback");
+    mInitialCallbackReceived = true;
 
     if (!stats.empty()) {
         mTransformHint = stats[0].transformHint;
@@ -185,7 +185,7 @@
         if (!stats.empty()) {
             mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
         } else {
-            ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
+            BQA_LOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
             mPendingReleaseItem.releaseFence = nullptr;
         }
         mBufferItemConsumer->releaseBuffer(mPendingReleaseItem.item,
@@ -198,7 +198,7 @@
     }
 
     if (mSubmitted.empty()) {
-        ALOGE("ERROR: callback with no corresponding submitted buffer item");
+        BQA_LOGE("ERROR: callback with no corresponding submitted buffer item");
     }
     mPendingReleaseItem.item = std::move(mSubmitted.front());
     mSubmitted.pop();
@@ -213,12 +213,18 @@
     ATRACE_CALL();
     BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));
 
-    if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
+    // Wait to acquire a buffer if there are no frames available or we have acquired the maximum
+    // number of buffers.
+    // As a special case, we wait for the first callback before acquiring the second buffer so we
+    // can ensure the first buffer is presented if multiple buffers are queued in succession.
+    if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
+        (!mInitialCallbackReceived && mNumAcquired == 1)) {
+        BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
         return;
     }
 
     if (mSurfaceControl == nullptr) {
-        ALOGE("ERROR : surface control is null");
+        BQA_LOGE("ERROR : surface control is null");
         return;
     }
 
@@ -245,6 +251,13 @@
         return;
     }
 
+    if (rejectBuffer(bufferItem)) {
+        BQA_LOGE("rejecting buffer: configured width=%d, height=%d, buffer{w=%d, h=%d}", mWidth,
+                 mHeight, buffer->getWidth(), buffer->getHeight());
+        mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+        return;
+    }
+
     mNumAcquired++;
     mSubmitted.push(bufferItem);
 
@@ -311,4 +324,13 @@
     mNextTransaction = t;
 }
 
+bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) const {
+    if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
+        // Only reject buffers if scaling mode is freeze.
+        return false;
+    }
+
+    // reject buffers if the buffer size doesn't match.
+    return item.mGraphicBuffer->getWidth() != mWidth || item.mGraphicBuffer->getHeight() != mHeight;
+}
 } // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 35c656a..5b1a018 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -94,6 +94,8 @@
 
     void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
     Rect computeCrop(const BufferItem& item);
+    // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
+    bool rejectBuffer(const BufferItem& item) const;
 
     std::string mName;
     sp<SurfaceControl> mSurfaceControl;
@@ -107,6 +109,7 @@
 
     int32_t mNumFrameAvailable GUARDED_BY(mMutex);
     int32_t mNumAcquired GUARDED_BY(mMutex);
+    bool mInitialCallbackReceived GUARDED_BY(mMutex) = false;
     struct PendingReleaseItem {
         BufferItem item;
         sp<Fence> releaseFence;