Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 400a20aa authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "SF: Add TextureFilteringTest"

parents 3a27e580 3886b07d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <binder/Parcelable.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>

namespace android::gui {

+1 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ cc_test {
        "SetFrameRateOverride_test.cpp",
        "SetGeometry_test.cpp",
        "Stress_test.cpp",
        "TextureFiltering_test.cpp",
        "VirtualDisplay_test.cpp",
        "WindowInfosListener_test.cpp",
    ],
+227 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <android/gui/ISurfaceComposerClient.h>
#include <gtest/gtest.h>
#include <gui/DisplayCaptureArgs.h>
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>

#include "LayerTransactionTest.h"

namespace android {

bool operator==(const Color& left, const Color& right) {
    return left.a == right.a && left.r == right.r && left.g == right.g && left.b == right.b;
}

class TextureFilteringTest : public LayerTransactionTest {
protected:
    virtual void SetUp() {
        LayerTransactionTest::SetUp();

        mParent = createLayer("test-parent", 100, 100,
                              gui::ISurfaceComposerClient::eFXSurfaceContainer);
        mLayer = createLayer("test-child", 100, 100,
                             gui::ISurfaceComposerClient::eFXSurfaceBufferState, mParent.get());
        sp<GraphicBuffer> buffer =
                sp<GraphicBuffer>::make(static_cast<uint32_t>(100), static_cast<uint32_t>(100),
                                        PIXEL_FORMAT_RGBA_8888, 1u,
                                        BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
                                                BufferUsage::COMPOSER_OVERLAY |
                                                BufferUsage::GPU_TEXTURE,
                                        "test");
        TransactionUtils::fillGraphicBufferColor(buffer, Rect{0, 0, 50, 100}, Color::RED);
        TransactionUtils::fillGraphicBufferColor(buffer, Rect{50, 0, 100, 100}, Color::BLUE);
        Transaction()
                .setBuffer(mLayer, buffer)
                .setDataspace(mLayer, ui::Dataspace::V0_SRGB)
                .setLayer(mLayer, INT32_MAX)
                .apply();
    }

    virtual void TearDown() { LayerTransactionTest::TearDown(); }

    void expectFiltered(Rect redRect, Rect blueRect) {
        // Check that at least some of the pixels in the red rectangle aren't solid red
        int redPixels = 0;
        for (int x = redRect.left; x < redRect.right; x++) {
            for (int y = redRect.top; y < redRect.bottom; y++) {
                redPixels += mCapture->getPixelColor(static_cast<uint32_t>(x),
                                                     static_cast<uint32_t>(y)) == Color::RED;
            }
        }
        ASSERT_LT(redPixels, redRect.getWidth() * redRect.getHeight());

        // Check that at least some of the pixels in the blue rectangle aren't solid blue
        int bluePixels = 0;
        for (int x = blueRect.left; x < blueRect.right; x++) {
            for (int y = blueRect.top; y < blueRect.bottom; y++) {
                bluePixels += mCapture->getPixelColor(static_cast<uint32_t>(x),
                                                      static_cast<uint32_t>(y)) == Color::BLUE;
            }
        }
        ASSERT_LT(bluePixels, blueRect.getWidth() * blueRect.getHeight());
    }

    sp<SurfaceControl> mParent;
    sp<SurfaceControl> mLayer;
    std::unique_ptr<ScreenCapture> mCapture;
};

TEST_F(TextureFilteringTest, NoFiltering) {
    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    captureArgs.width = 100;
    captureArgs.height = 100;
    captureArgs.sourceCrop = Rect{100, 100};
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    mCapture->expectColor(Rect{0, 0, 50, 100}, Color::RED);
    mCapture->expectColor(Rect{50, 0, 100, 100}, Color::BLUE);
}

TEST_F(TextureFilteringTest, BufferCropNoFiltering) {
    Transaction().setBufferCrop(mLayer, Rect{0, 0, 100, 100}).apply();

    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    captureArgs.width = 100;
    captureArgs.height = 100;
    captureArgs.sourceCrop = Rect{0, 0, 100, 100};
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    mCapture->expectColor(Rect{0, 0, 50, 100}, Color::RED);
    mCapture->expectColor(Rect{50, 0, 100, 100}, Color::BLUE);
}

// Expect filtering because the buffer is stretched to the layer's bounds.
TEST_F(TextureFilteringTest, BufferCropIsFiltered) {
    Transaction().setBufferCrop(mLayer, Rect{25, 25, 75, 75}).apply();

    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    captureArgs.width = 100;
    captureArgs.height = 100;
    captureArgs.sourceCrop = Rect{0, 0, 100, 100};
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    expectFiltered({0, 0, 50, 100}, {50, 0, 100, 100});
}

// Expect filtering because the output source crop is stretched to the output buffer's size.
TEST_F(TextureFilteringTest, OutputSourceCropIsFiltered) {
    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    captureArgs.width = 100;
    captureArgs.height = 100;
    captureArgs.sourceCrop = Rect{25, 25, 75, 75};
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    expectFiltered({0, 0, 50, 100}, {50, 0, 100, 100});
}

// Expect filtering because the layer crop and output source crop are stretched to the output
// buffer's size.
TEST_F(TextureFilteringTest, LayerCropOutputSourceCropIsFiltered) {
    Transaction().setCrop(mLayer, Rect{25, 25, 75, 75}).apply();

    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    captureArgs.width = 100;
    captureArgs.height = 100;
    captureArgs.sourceCrop = Rect{25, 25, 75, 75};
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    expectFiltered({0, 0, 50, 100}, {50, 0, 100, 100});
}

// Expect filtering because the layer is scaled up.
TEST_F(TextureFilteringTest, LayerCaptureWithScalingIsFiltered) {
    LayerCaptureArgs captureArgs;
    captureArgs.layerHandle = mLayer->getHandle();
    captureArgs.frameScaleX = 2;
    captureArgs.frameScaleY = 2;
    ScreenCapture::captureLayers(&mCapture, captureArgs);

    expectFiltered({0, 0, 100, 200}, {100, 0, 200, 200});
}

// Expect no filtering because the output buffer's size matches the source crop.
TEST_F(TextureFilteringTest, LayerCaptureOutputSourceCropNoFiltering) {
    LayerCaptureArgs captureArgs;
    captureArgs.layerHandle = mLayer->getHandle();
    captureArgs.sourceCrop = Rect{25, 25, 75, 75};
    ScreenCapture::captureLayers(&mCapture, captureArgs);

    mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED);
    mCapture->expectColor(Rect{25, 0, 50, 50}, Color::BLUE);
}

// Expect no filtering because the output buffer's size matches the source crop (with a cropped
// layer).
TEST_F(TextureFilteringTest, LayerCaptureWithCropNoFiltering) {
    Transaction().setCrop(mLayer, Rect{10, 10, 90, 90}).apply();

    LayerCaptureArgs captureArgs;
    captureArgs.layerHandle = mLayer->getHandle();
    captureArgs.sourceCrop = Rect{25, 25, 75, 75};
    ScreenCapture::captureLayers(&mCapture, captureArgs);

    mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED);
    mCapture->expectColor(Rect{25, 0, 50, 50}, Color::BLUE);
}

// Expect no filtering because the output source crop and output buffer are the same size.
TEST_F(TextureFilteringTest, OutputSourceCropDisplayFrameMatchNoFiltering) {
    // Transaction().setCrop(mLayer, Rect{25, 25, 75, 75}).apply();

    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    captureArgs.width = 50;
    captureArgs.height = 50;
    captureArgs.sourceCrop = Rect{25, 25, 75, 75};
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    mCapture->expectColor(Rect{0, 0, 25, 50}, Color::RED);
    mCapture->expectColor(Rect{25, 0, 50, 50}, Color::BLUE);
}

// Expect no filtering because the layer crop shouldn't scale the layer.
TEST_F(TextureFilteringTest, LayerCropDisplayFrameMatchNoFiltering) {
    Transaction().setCrop(mLayer, Rect{25, 25, 75, 75}).apply();

    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    mCapture->expectColor(Rect{25, 25, 50, 75}, Color::RED);
    mCapture->expectColor(Rect{50, 25, 75, 75}, Color::BLUE);
}

// Expect no filtering because the parent layer crop shouldn't scale the layer.
TEST_F(TextureFilteringTest, ParentCropNoFiltering) {
    Transaction().setCrop(mParent, Rect{25, 25, 75, 75}).apply();

    gui::DisplayCaptureArgs captureArgs;
    captureArgs.displayToken = mDisplay;
    ScreenCapture::captureDisplay(&mCapture, captureArgs);

    mCapture->expectColor(Rect{25, 25, 50, 75}, Color::RED);
    mCapture->expectColor(Rect{50, 25, 75, 75}, Color::BLUE);
}

} // namespace android