Add VTS for new API for clearing buffer slots

Bug: 262041682
Bug: 258196272
Test: VtsHalGraphicsComposer3_TargetTest
Change-Id: If7e5fea56734f3ae7b4aae7378f4aea0eacc8e32
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 93d9693..166127d 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -379,9 +379,16 @@
 }
 
 TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
-    const auto& [status, readbackBufferAttributes] =
+    const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+    ASSERT_TRUE(versionStatus.isOk());
+    if (version == 1) {
+        GTEST_SUCCEED() << "Device does not support the new API for clearing buffer slots";
+        return;
+    }
+
+    const auto& [readbackStatus, readbackBufferAttributes] =
             mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
-    if (!status.isOk()) {
+    if (!readbackStatus.isOk()) {
         GTEST_SUCCEED() << "Readback not supported";
         return;
     }
@@ -396,9 +403,6 @@
     // no fence needed for the readback buffer
     ScopedFileDescriptor noFence(-1);
 
-    sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
-    ASSERT_NE(nullptr, clearSlotBuffer);
-
     // red buffer
     uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
     sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
@@ -412,10 +416,16 @@
     int blueFence;
     ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
 
+    // green buffer
+    sp<GraphicBuffer> greenBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, greenBuffer);
+    int greenFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(greenBuffer, GREEN, &greenFence));
+
     // layer defaults
     common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
     int64_t display = getPrimaryDisplayId();
-    auto [layerStatus, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), 3);
+    const auto& [layerStatus, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), 3);
     ASSERT_TRUE(layerStatus.isOk());
     mWriter->setLayerDisplayFrame(display, layer, rectFullDisplay);
     mWriter->setLayerCompositionType(display, layer, Composition::DEVICE);
@@ -454,13 +464,12 @@
         ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
     }
 
-    // clear the slot for the blue buffer
-    // should still be red
+    // change the layer to the green buffer
+    // should be green
     {
         auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
         ASSERT_TRUE(status.isOk());
-        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
-                                              /*fence*/ -1);
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, greenBuffer->handle, greenFence);
         mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
         execute();
         ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
@@ -469,17 +478,106 @@
         execute();
         auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
         ASSERT_TRUE(fenceStatus.isOk());
-        ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
     }
 
-    // clear the slot for the red buffer, and set the buffer with the same slot to the blue buffer
+    // clear the slots for all buffers
+    // should still be green since the active buffer should not be cleared by the HAL implementation
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBufferSlotsToClear(display, layer, /*slotsToClear*/ {0, 1, 2});
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
+    }
+
+    // clear the slot for the green buffer, and set the buffer with the same slot to the blue buffer
     // should be blue
     {
         auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
         ASSERT_TRUE(status.isOk());
-        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
-                                              /*fence*/ -1);
-        mWriter->setLayerBuffer(display, layer, /*slot*/ 1, blueBuffer->handle, blueFence);
+        mWriter->setLayerBufferSlotsToClear(display, layer, /*slotsToClear*/ {2});
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+    }
+}
+
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear_backwardsCompatible) {
+    const auto& [versionStatus, version] = mComposerClient->getInterfaceVersion();
+    ASSERT_TRUE(versionStatus.isOk());
+    if (version > 1) {
+        GTEST_SUCCEED() << "Device does not need a backwards compatible way to clear buffer slots";
+        return;
+    }
+
+    const auto& [readbackStatus, readbackBufferAttributes] =
+            mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
+    if (!readbackStatus.isOk()) {
+        GTEST_SUCCEED() << "Readback not supported";
+        return;
+    }
+
+    sp<GraphicBuffer> readbackBuffer;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+            readbackBufferAttributes, getPrimaryDisplay(), &readbackBuffer));
+    if (readbackBuffer == nullptr) {
+        GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+        return;
+    }
+    // no fence needed for the readback buffer
+    ScopedFileDescriptor noFence(-1);
+
+    sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
+    ASSERT_NE(nullptr, clearSlotBuffer);
+
+    // red buffer
+    uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+    sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, redBuffer);
+    int redFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+    // blue buffer
+    sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, blueBuffer);
+    int blueFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+    // green buffer
+    sp<GraphicBuffer> greenBuffer = allocateBuffer(usage);
+    ASSERT_NE(nullptr, greenBuffer);
+    int greenFence;
+    ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(greenBuffer, GREEN, &greenFence));
+
+    // layer defaults
+    common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
+    int64_t display = getPrimaryDisplayId();
+    const auto& [layerStatus, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), 3);
+    ASSERT_TRUE(layerStatus.isOk());
+    mWriter->setLayerDisplayFrame(display, layer, rectFullDisplay);
+    mWriter->setLayerCompositionType(display, layer, Composition::DEVICE);
+
+    // set the layer to the blue buffer
+    // should be blue
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 0, blueBuffer->handle, blueFence);
         mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
         execute();
         ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
@@ -491,27 +589,82 @@
         ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
     }
 
-    // clear the slot for the now-blue buffer
-    // should be black (no buffer)
-    // TODO(b/262037933) Ensure we never clear the active buffer's slot with the placeholder buffer
-    // by setting the layer to the color black
+    // change the layer to the red buffer
+    // should be red
     {
         auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
         ASSERT_TRUE(status.isOk());
-        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
-                                              /*fence*/ -1);
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 1, redBuffer->handle, redFence);
         mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
         execute();
-        if (!mReader.takeChangedCompositionTypes(display).empty()) {
-            GTEST_SUCCEED();
-            return;
-        }
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
         ASSERT_TRUE(mReader.takeErrors().empty());
         mWriter->presentDisplay(display);
         execute();
         auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
         ASSERT_TRUE(fenceStatus.isOk());
-        ReadbackHelper::compareColorToBuffer(BLACK, readbackBuffer, fence);
+        ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+    }
+
+    // change the layer to the green buffer
+    // should be green
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, greenBuffer->handle, greenFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
+    }
+
+    // clear the slot for the blue buffer
+    // should still be green
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+                                              /*fence*/ -1);
+        // SurfaceFlinger will re-set the active buffer slot after other buffer slots are cleared
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 2, /*handle*/ nullptr,
+                                              /*fence*/ -1);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(GREEN, readbackBuffer, fence);
+    }
+
+    // clear the slot for all buffers, and set the buffer with the same slot as the green buffer
+    // should be blue now
+    {
+        auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+        ASSERT_TRUE(status.isOk());
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+                                              /*fence*/ -1);
+        mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
+                                              /*fence*/ -1);
+        // SurfaceFlinger will never clear the active buffer (slot 2), but will free up the
+        // buffer slot so it will be re-used for the next setLayerBuffer command
+        mWriter->setLayerBuffer(display, layer, /*slot*/ 2, blueBuffer->handle, blueFence);
+        mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+        execute();
+        ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+        ASSERT_TRUE(mReader.takeErrors().empty());
+        mWriter->presentDisplay(display);
+        execute();
+        auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+        ASSERT_TRUE(fenceStatus.isOk());
+        ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
     }
 }