Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)
Bug: 166295507
Merged-In: I70ea776b8589ac3a7982c710c5c8b2941d86e55b
Change-Id: Ic1d535e9d2d6f80d95215240dbdb024995b045f8
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 53a3611..fe2af80 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -18,11 +18,25 @@
test_suites: ["device-tests"],
srcs: [
"BufferGenerator.cpp",
+ "CommonTypes_test.cpp",
"Credentials_test.cpp",
+ "DereferenceSurfaceControl_test.cpp",
+ "DisplayConfigs_test.cpp",
+ "EffectLayer_test.cpp",
"InvalidHandles_test.cpp",
+ "LayerCallback_test.cpp",
+ "LayerRenderTypeTransaction_test.cpp",
+ "LayerTransaction_test.cpp",
+ "LayerTypeAndRenderTypeTransaction_test.cpp",
+ "LayerTypeTransaction_test.cpp",
+ "LayerUpdate_test.cpp",
+ "MirrorLayer_test.cpp",
+ "MultiDisplayLayerBounds_test.cpp",
+ "RelativeZ_test.cpp",
+ "SetFrameRate_test.cpp",
+ "SetGeometry_test.cpp",
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
- "Transaction_test.cpp",
"VirtualDisplay_test.cpp",
],
data: ["SurfaceFlinger_test.filter"],
@@ -30,6 +44,52 @@
"libtrace_proto",
],
shared_libs: [
+ "android.hardware.graphics.common-ndk_platform",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.composer@2.1",
+ "libandroid",
+ "libbinder",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libgui",
+ "liblayers_proto",
+ "liblog",
+ "libnativewindow",
+ "libprotobuf-cpp-full",
+ "libui",
+ "libutils",
+ ],
+ header_libs: [
+ "libnativewindow_headers",
+ ],
+}
+
+cc_defaults {
+ name: "ipc_defaults",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
+ name: "IPC_test",
+ defaults: ["ipc_defaults"],
+ test_suites: ["device-tests"],
+ srcs: [
+ "BufferGenerator.cpp",
+ "IPC_test.cpp",
+ ],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ shared_libs: [
"libandroid",
"libbinder",
"libcutils",
@@ -39,17 +99,18 @@
"liblayers_proto",
"liblog",
"libprotobuf-cpp-full",
- "libtimestats_proto",
"libui",
"libutils",
- ]
-
+ ],
+ cpp_std: "experimental",
+ gnu_extensions: false,
}
subdirs = [
"fakehwc",
"hwc2",
"unittests",
+ "utils",
"vsync",
"waitforvsync",
]
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 8ddda60..4868c12 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gui/BufferItemConsumer.h>
#include <gui/Surface.h>
@@ -84,7 +88,7 @@
sp<Surface> mSurface;
};
-/* Used to generate valid fences. It is not possible to create a dummy sync
+/* Used to generate valid fences. It is not possible to create a placeholder sync
* fence for testing. Egl can generate buffers along with a valid fence.
* The buffer cannot be guaranteed to be the same format across all devices so
* a CPU filled buffer is used instead. The Egl fence is used along with the
@@ -379,3 +383,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/CommonTypes_test.cpp b/services/surfaceflinger/tests/CommonTypes_test.cpp
new file mode 100644
index 0000000..25b4615
--- /dev/null
+++ b/services/surfaceflinger/tests/CommonTypes_test.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2019 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 <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+
+#include <android/data_space.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
+
+using AidlBlendMode = aidl::android::hardware::graphics::common::BlendMode;
+using AidlDataspace = aidl::android::hardware::graphics::common::Dataspace;
+
+using HidlBlendMode = android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode;
+using HidlDataspace = android::hardware::graphics::common::V1_2::Dataspace;
+
+static_assert(static_cast<uint32_t>(AidlBlendMode::INVALID) ==
+ static_cast<uint32_t>(HidlBlendMode::INVALID));
+static_assert(static_cast<uint32_t>(AidlBlendMode::NONE) ==
+ static_cast<uint32_t>(HidlBlendMode::NONE));
+static_assert(static_cast<uint32_t>(AidlBlendMode::PREMULTIPLIED) ==
+ static_cast<uint32_t>(HidlBlendMode::PREMULTIPLIED));
+static_assert(static_cast<uint32_t>(AidlBlendMode::COVERAGE) ==
+ static_cast<uint32_t>(HidlBlendMode::COVERAGE));
+
+static_assert(static_cast<uint32_t>(ADATASPACE_UNKNOWN) ==
+ static_cast<uint32_t>(AidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB_LINEAR) ==
+ static_cast<uint32_t>(AidlDataspace::SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB) == static_cast<uint32_t>(AidlDataspace::SRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB) ==
+ static_cast<uint32_t>(AidlDataspace::SCRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_DISPLAY_P3) ==
+ static_cast<uint32_t>(AidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020_PQ) ==
+ static_cast<uint32_t>(AidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(ADATASPACE_ADOBE_RGB) ==
+ static_cast<uint32_t>(AidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020) ==
+ static_cast<uint32_t>(AidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT709) ==
+ static_cast<uint32_t>(AidlDataspace::BT709));
+static_assert(static_cast<uint32_t>(ADATASPACE_DCI_P3) ==
+ static_cast<uint32_t>(AidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB_LINEAR) ==
+ static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR));
+
+static_assert(static_cast<uint32_t>(ADATASPACE_UNKNOWN) ==
+ static_cast<uint32_t>(HidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_DISPLAY_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020_PQ) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(ADATASPACE_ADOBE_RGB) ==
+ static_cast<uint32_t>(HidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT709) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT709));
+static_assert(static_cast<uint32_t>(ADATASPACE_DCI_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
+
+static_assert(static_cast<uint32_t>(AidlDataspace::UNKNOWN) ==
+ static_cast<uint32_t>(HidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(AidlDataspace::ARBITRARY) ==
+ static_cast<uint32_t>(HidlDataspace::ARBITRARY));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_SHIFT) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_MASK) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_UNSPECIFIED) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT709) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT709));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_625) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_625));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_625_UNADJUSTED) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_625_UNADJUSTED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_525) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_525));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_525_UNADJUSTED) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_525_UNADJUSTED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT470M) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_BT470M));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_FILM) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_FILM));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_DCI_P3) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_DCI_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_ADOBE_RGB) ==
+ static_cast<uint32_t>(HidlDataspace::STANDARD_ADOBE_RGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SHIFT) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_MASK) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_UNSPECIFIED) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SRGB) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_SRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SMPTE_170M) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_SMPTE_170M));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_2) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_2));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_6) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_6));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_8) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_8));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_ST2084) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_ST2084));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_HLG) ==
+ static_cast<uint32_t>(HidlDataspace::TRANSFER_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_SHIFT) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_MASK) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_UNSPECIFIED) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_FULL) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_FULL));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_LIMITED) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_LIMITED));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_EXTENDED) ==
+ static_cast<uint32_t>(HidlDataspace::RANGE_EXTENDED));
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB) ==
+ static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::JFIF) ==
+ static_cast<uint32_t>(HidlDataspace::V0_JFIF));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_625) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT601_625));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_525) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT601_525));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT709) ==
+ static_cast<uint32_t>(HidlDataspace::V0_BT709));
+static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::DCI_P3_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_P3_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_P3_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_P3) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::ADOBE_RGB) ==
+ static_cast<uint32_t>(HidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_LINEAR) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_PQ) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(AidlDataspace::DEPTH) ==
+ static_cast<uint32_t>(HidlDataspace::DEPTH));
+static_assert(static_cast<uint32_t>(AidlDataspace::SENSOR) ==
+ static_cast<uint32_t>(HidlDataspace::SENSOR));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_ITU));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU_PQ) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_ITU_PQ));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU_HLG) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_ITU_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_HLG) ==
+ static_cast<uint32_t>(HidlDataspace::BT2020_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_BT2020) ==
+ static_cast<uint32_t>(HidlDataspace::DISPLAY_BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::DYNAMIC_DEPTH) ==
+ static_cast<uint32_t>(HidlDataspace::DYNAMIC_DEPTH));
+static_assert(static_cast<uint32_t>(AidlDataspace::JPEG_APP_SEGMENTS) ==
+ static_cast<uint32_t>(HidlDataspace::JPEG_APP_SEGMENTS));
+static_assert(static_cast<uint32_t>(AidlDataspace::HEIF) ==
+ static_cast<uint32_t>(HidlDataspace::HEIF));
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index b667a74..c136708 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -1,20 +1,15 @@
-#include <algorithm>
-#include <functional>
-#include <limits>
-#include <ostream>
-
#include <gtest/gtest.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-
#include <private/android_filesystem_config.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <utils/String8.h>
+#include <functional>
+
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
@@ -23,7 +18,6 @@
namespace {
const String8 DISPLAY_NAME("Credentials Display Test");
const String8 SURFACE_NAME("Test Surface Name");
-const uint32_t ROTATION = 0;
const float FRAME_SCALE = 1.0f;
} // namespace
@@ -32,6 +26,10 @@
* Methods like EnableVsyncInjections and InjectVsync are not tested since they do not
* return anything meaningful.
*/
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
class CredentialsTest : public ::testing::Test {
protected:
void SetUp() override {
@@ -64,14 +62,13 @@
mDisplay = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(mDisplay == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
- const ssize_t displayWidth = info.w;
- const ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
// Background surface
mBGSurfaceControl =
- mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ mComposerClient->createSurface(SURFACE_NAME, config.resolution.getWidth(),
+ config.resolution.getHeight(),
PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
@@ -185,10 +182,10 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_TRUE(display != nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display));
@@ -215,10 +212,24 @@
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
}
-TEST_F(CredentialsTest, SetActiveConfigTest) {
+TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ int32_t defaultConfig;
+ float primaryFpsMin;
+ float primaryFpsMax;
+ float appRequestFpsMin;
+ float appRequestFpsMax;
+ status_t res =
+ SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+ &primaryFpsMin, &primaryFpsMax,
+ &appRequestFpsMin,
+ &appRequestFpsMax);
+ ASSERT_EQ(res, NO_ERROR);
std::function<status_t()> condition = [=]() {
- return SurfaceComposerClient::setActiveConfig(display, 0);
+ return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+ primaryFpsMin, primaryFpsMax,
+ appRequestFpsMin,
+ appRequestFpsMax);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
@@ -245,24 +256,13 @@
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
}
-TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) {
- setupVirtualDisplay();
-
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
- SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
- // This test currently fails. TODO(b/112002626): Find a way to properly create
- // a display in the test environment, so that destroy display can remove it.
- ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
-}
-
TEST_F(CredentialsTest, CaptureTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
sp<GraphicBuffer> outBuffer;
return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/,
- 0 /*reqHeight*/, false, ROTATION, &outBuffer);
+ 0 /*reqHeight*/, false, ui::ROTATION_0, &outBuffer);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
@@ -274,7 +274,7 @@
sp<GraphicBuffer> outBuffer;
return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(),
ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
- Rect(), FRAME_SCALE, &outBuffer);
+ Rect(0, 0, 1, 1), FRAME_SCALE, &outBuffer);
};
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
}
@@ -363,3 +363,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
new file mode 100644
index 0000000..46b98f9
--- /dev/null
+++ b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class DereferenceSurfaceControlTest : public LayerTransactionTest {
+protected:
+ void SetUp() override {
+ LayerTransactionTest::SetUp();
+ bgLayer = createLayer("BG layer", 20, 20);
+ fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
+ fgLayer = createLayer("FG layer", 20, 20);
+ fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
+ Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
+ {
+ SCOPED_TRACE("before anything");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+ }
+ }
+ void TearDown() override {
+ LayerTransactionTest::TearDown();
+ bgLayer = 0;
+ fgLayer = 0;
+ }
+
+ sp<SurfaceControl> bgLayer;
+ sp<SurfaceControl> fgLayer;
+};
+
+TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
+ fgLayer = nullptr;
+ {
+ SCOPED_TRACE("after setting null");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
+ }
+}
+
+TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
+ auto transaction = Transaction().show(fgLayer);
+ fgLayer = nullptr;
+ {
+ SCOPED_TRACE("after setting null");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+ }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
new file mode 100644
index 0000000..debfe83
--- /dev/null
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <thread>
+#include "LayerTransactionTest.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+/**
+ * Test class for setting display configs and passing around refresh rate ranges.
+ */
+class RefreshRateRangeTest : public ::testing::Test {
+protected:
+ void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
+
+ sp<IBinder> mDisplayToken;
+};
+
+TEST_F(RefreshRateRangeTest, setAllConfigs) {
+ int32_t initialDefaultConfig;
+ float initialPrimaryMin;
+ float initialPrimaryMax;
+ float initialAppRequestMin;
+ float initialAppRequestMax;
+ status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+ &initialDefaultConfig,
+ &initialPrimaryMin,
+ &initialPrimaryMax,
+ &initialAppRequestMin,
+ &initialAppRequestMax);
+ ASSERT_EQ(res, NO_ERROR);
+
+ Vector<DisplayConfig> configs;
+ res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+ ASSERT_EQ(res, NO_ERROR);
+
+ for (size_t i = 0; i < configs.size(); i++) {
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate);
+ ASSERT_EQ(res, NO_ERROR);
+
+ int defaultConfig;
+ float primaryRefreshRateMin;
+ float primaryRefreshRateMax;
+ float appRequestRefreshRateMin;
+ float appRequestRefreshRateMax;
+ res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+ &primaryRefreshRateMin,
+ &primaryRefreshRateMax,
+ &appRequestRefreshRateMin,
+ &appRequestRefreshRateMax);
+ ASSERT_EQ(res, NO_ERROR);
+ ASSERT_EQ(defaultConfig, i);
+ ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
+ ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
+ }
+
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
+ initialPrimaryMin, initialPrimaryMax,
+ initialAppRequestMin,
+ initialAppRequestMax);
+ ASSERT_EQ(res, NO_ERROR);
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
new file mode 100644
index 0000000..3dca391
--- /dev/null
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class EffectLayerTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ mParentLayer = createColorLayer("Parent layer", Color::RED);
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+ t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+ t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mParentLayer = 0;
+ }
+
+ sp<SurfaceControl> mParentLayer;
+};
+
+TEST_F(EffectLayerTest, DefaultEffectLayerHasSolidBlackFill) {
+ sp<SurfaceControl> effectLayer =
+ mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect,
+ mParentLayer.get());
+
+ EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+ asTransaction([&](Transaction& t) {
+ t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+ t.show(effectLayer);
+ });
+
+ {
+ SCOPED_TRACE("Default effect Layer has solid black fill");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 400, 400), Color::BLACK);
+ }
+}
+
+TEST_F(EffectLayerTest, EffectLayerWithNoFill) {
+ sp<SurfaceControl> effectLayer =
+ mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect |
+ ISurfaceComposerClient::eNoColorFill,
+ mParentLayer.get());
+
+ EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+ asTransaction([&](Transaction& t) {
+ t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+ t.show(effectLayer);
+ });
+
+ {
+ SCOPED_TRACE("Effect layer with nofill option is transparent");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 400, 400), Color::RED);
+ }
+}
+
+TEST_F(EffectLayerTest, EffectLayerCanSetColor) {
+ sp<SurfaceControl> effectLayer =
+ mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect |
+ ISurfaceComposerClient::eNoColorFill,
+ mParentLayer.get());
+
+ EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+ asTransaction([&](Transaction& t) {
+ t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+ t.setColor(effectLayer,
+ half3{Color::GREEN.r / 255.0f, Color::GREEN.g / 255.0f,
+ Color::GREEN.b / 255.0f});
+ t.show(effectLayer);
+ });
+
+ {
+ SCOPED_TRACE("Effect Layer can set color");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 400, 400), Color::GREEN);
+ }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
new file mode 100644
index 0000000..4023c66
--- /dev/null
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2019 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 <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+#include <utils/String8.h>
+
+#include <limits>
+
+#include "BufferGenerator.h"
+#include "utils/CallbackUtils.h"
+#include "utils/ColorUtils.h"
+#include "utils/TransactionUtils.h"
+
+namespace android {
+
+namespace test {
+
+using Transaction = SurfaceComposerClient::Transaction;
+using CallbackInfo = SurfaceComposerClient::CallbackInfo;
+using TCLHash = SurfaceComposerClient::TCLHash;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class TransactionHelper : public Transaction {
+public:
+ size_t getNumListeners() { return mListenerCallbacks.size(); }
+
+ std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+ getListenerCallbacks() {
+ return mListenerCallbacks;
+ }
+};
+
+class IPCTestUtils {
+public:
+ static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState = false);
+ static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence);
+};
+
+class IIPCTest : public IInterface {
+public:
+ DECLARE_META_INTERFACE(IPCTest)
+ enum class Tag : uint32_t {
+ SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
+ InitClient,
+ CreateTransaction,
+ MergeAndApply,
+ VerifyCallbacks,
+ CleanUp,
+ Last,
+ };
+
+ virtual status_t setDeathToken(sp<IBinder>& token) = 0;
+
+ virtual status_t initClient() = 0;
+
+ virtual status_t createTransaction(TransactionHelper* outTransaction, uint32_t width,
+ uint32_t height) = 0;
+
+ virtual status_t mergeAndApply(TransactionHelper transaction) = 0;
+
+ virtual status_t verifyCallbacks() = 0;
+
+ virtual status_t cleanUp() = 0;
+};
+
+class BpIPCTest : public SafeBpInterface<IIPCTest> {
+public:
+ explicit BpIPCTest(const sp<IBinder>& impl) : SafeBpInterface<IIPCTest>(impl, "BpIPCTest") {}
+
+ status_t setDeathToken(sp<IBinder>& token) {
+ return callRemote<decltype(&IIPCTest::setDeathToken)>(Tag::SetDeathToken, token);
+ }
+
+ status_t initClient() { return callRemote<decltype(&IIPCTest::initClient)>(Tag::InitClient); }
+
+ status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) {
+ return callRemote<decltype(&IIPCTest::createTransaction)>(Tag::CreateTransaction,
+ transaction, width, height);
+ }
+
+ status_t mergeAndApply(TransactionHelper transaction) {
+ return callRemote<decltype(&IIPCTest::mergeAndApply)>(Tag::MergeAndApply, transaction);
+ }
+
+ status_t verifyCallbacks() {
+ return callRemote<decltype(&IIPCTest::verifyCallbacks)>(Tag::VerifyCallbacks);
+ }
+
+ status_t cleanUp() { return callRemote<decltype(&IIPCTest::cleanUp)>(Tag::CleanUp); }
+};
+
+IMPLEMENT_META_INTERFACE(IPCTest, "android.gfx.tests.IIPCTest")
+
+class onTestDeath : public IBinder::DeathRecipient {
+public:
+ void binderDied(const wp<IBinder>& /*who*/) override {
+ ALOGE("onTestDeath::binderDied, exiting");
+ exit(0);
+ }
+};
+
+sp<onTestDeath> getDeathToken() {
+ static sp<onTestDeath> token = new onTestDeath;
+ return token;
+}
+
+class BnIPCTest : public SafeBnInterface<IIPCTest> {
+public:
+ BnIPCTest() : SafeBnInterface("BnIPCTest") {}
+
+ status_t setDeathToken(sp<IBinder>& token) override {
+ return token->linkToDeath(getDeathToken());
+ }
+
+ status_t initClient() override {
+ mClient = new SurfaceComposerClient;
+ auto err = mClient->initCheck();
+ return err;
+ }
+
+ status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) {
+ if (transaction == nullptr) {
+ ALOGE("Error in createTransaction: transaction is nullptr");
+ return BAD_VALUE;
+ }
+ mSurfaceControl = mClient->createSurface(String8("parentProcessSurface"), 0, 0,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+ sp<GraphicBuffer> gb;
+ sp<Fence> fence;
+ int err = IPCTestUtils::getBuffer(&gb, &fence);
+ if (err != NO_ERROR) return err;
+
+ TransactionUtils::fillGraphicBufferColor(gb,
+ {0, 0, static_cast<int32_t>(width),
+ static_cast<int32_t>(height)},
+ Color::RED);
+ transaction->setLayerStack(mSurfaceControl, 0)
+ .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
+ .setFrame(mSurfaceControl, Rect(0, 0, width, height))
+ .setBuffer(mSurfaceControl, gb)
+ .setAcquireFence(mSurfaceControl, fence)
+ .show(mSurfaceControl)
+ .addTransactionCompletedCallback(mCallbackHelper.function,
+ mCallbackHelper.getContext());
+ return NO_ERROR;
+ }
+
+ status_t mergeAndApply(TransactionHelper /*transaction*/) {
+ // transaction.apply();
+ return NO_ERROR;
+ }
+
+ status_t verifyCallbacks() {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, mSurfaceControl);
+ EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(mCallbackHelper, expected, true));
+ return NO_ERROR;
+ }
+
+ status_t cleanUp() {
+ if (mClient) mClient->dispose();
+ mSurfaceControl = nullptr;
+ IPCThreadState::self()->stopProcess();
+ return NO_ERROR;
+ }
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t /*flags*/) override {
+ EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+ EXPECT_LT(code, static_cast<uint32_t>(IIPCTest::Tag::Last));
+ switch (static_cast<IIPCTest::Tag>(code)) {
+ case IIPCTest::Tag::SetDeathToken:
+ return callLocal(data, reply, &IIPCTest::setDeathToken);
+ case IIPCTest::Tag::InitClient:
+ return callLocal(data, reply, &IIPCTest::initClient);
+ case IIPCTest::Tag::CreateTransaction:
+ return callLocal(data, reply, &IIPCTest::createTransaction);
+ case IIPCTest::Tag::MergeAndApply:
+ return callLocal(data, reply, &IIPCTest::mergeAndApply);
+ case IIPCTest::Tag::VerifyCallbacks:
+ return callLocal(data, reply, &IIPCTest::verifyCallbacks);
+ case IIPCTest::Tag::CleanUp:
+ return callLocal(data, reply, &IIPCTest::cleanUp);
+ default:
+ return UNKNOWN_ERROR;
+ }
+ }
+
+private:
+ sp<SurfaceComposerClient> mClient;
+ sp<SurfaceControl> mSurfaceControl;
+ CallbackHelper mCallbackHelper;
+};
+
+class IPCTest : public ::testing::Test {
+public:
+ IPCTest() : mDeathRecipient(new BBinder), mRemote(initRemoteService()) {
+ ProcessState::self()->startThreadPool();
+ }
+ void SetUp() {
+ mClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mPrimaryDisplay = mClient->getInternalDisplayToken();
+ DisplayConfig config;
+ mClient->getActiveDisplayConfig(mPrimaryDisplay, &config);
+ mDisplayWidth = config.resolution.getWidth();
+ mDisplayHeight = config.resolution.getHeight();
+
+ Transaction setupTransaction;
+ setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
+ setupTransaction.apply();
+ }
+
+protected:
+ sp<IIPCTest> initRemoteService();
+
+ sp<IBinder> mDeathRecipient;
+ sp<IIPCTest> mRemote;
+ sp<SurfaceComposerClient> mClient;
+ sp<IBinder> mPrimaryDisplay;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
+ sp<SurfaceControl> sc;
+};
+
+status_t IPCTestUtils::getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+ static BufferGenerator bufferGenerator;
+ return bufferGenerator.get(outBuffer, outFence);
+}
+
+void IPCTestUtils::waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState) {
+ CallbackData callbackData;
+ ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
+
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+}
+
+sp<IIPCTest> IPCTest::initRemoteService() {
+ static std::mutex mMutex;
+ static sp<IIPCTest> remote;
+ const String16 serviceName("IPCTest");
+
+ std::unique_lock<decltype(mMutex)> lock;
+ if (remote == nullptr) {
+ pid_t forkPid = fork();
+ EXPECT_NE(forkPid, -1);
+
+ if (forkPid == 0) {
+ sp<IIPCTest> nativeService = new BnIPCTest;
+ if (!nativeService) {
+ ALOGE("null service...");
+ }
+ status_t err = defaultServiceManager()->addService(serviceName,
+ IInterface::asBinder(nativeService));
+ if (err != NO_ERROR) {
+ ALOGE("failed to add service: %d", err);
+ }
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ [&]() { exit(0); }();
+ }
+ sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
+ remote = interface_cast<IIPCTest>(binder);
+ remote->setDeathToken(mDeathRecipient);
+ }
+ return remote;
+}
+
+TEST_F(IPCTest, MergeBasic) {
+ CallbackHelper helper1;
+ sc = mClient->createSurface(String8("parentProcessSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+ sp<GraphicBuffer> gb;
+ sp<Fence> fence;
+ int err = IPCTestUtils::getBuffer(&gb, &fence);
+ ASSERT_EQ(NO_ERROR, err);
+ TransactionUtils::fillGraphicBufferColor(gb,
+ {0, 0, static_cast<int32_t>(mDisplayWidth),
+ static_cast<int32_t>(mDisplayHeight)},
+ Color::RED);
+
+ Transaction transaction;
+ transaction.setLayerStack(sc, 0)
+ .setLayer(sc, std::numeric_limits<int32_t>::max() - 1)
+ .setBuffer(sc, gb)
+ .setAcquireFence(sc, fence)
+ .show(sc)
+ .addTransactionCompletedCallback(helper1.function, helper1.getContext());
+
+ TransactionHelper remote;
+ mRemote->initClient();
+ mRemote->createTransaction(&remote, mDisplayWidth / 2, mDisplayHeight / 2);
+ ASSERT_EQ(1, remote.getNumListeners());
+ auto remoteListenerCallbacks = remote.getListenerCallbacks();
+ auto remoteCallback = remoteListenerCallbacks.begin();
+ auto remoteCallbackInfo = remoteCallback->second;
+ auto remoteListenerScs = remoteCallbackInfo.surfaceControls;
+ ASSERT_EQ(1, remoteCallbackInfo.callbackIds.size());
+ ASSERT_EQ(1, remoteListenerScs.size());
+
+ sp<SurfaceControl> remoteSc = *(remoteListenerScs.begin());
+ transaction.merge(std::move(remote));
+ transaction.apply();
+
+ sleep(1);
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, sc);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, remoteSc);
+ EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(helper1, expected, true));
+
+ mRemote->verifyCallbacks();
+ mRemote->cleanUp();
+}
+
+} // namespace test
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
new file mode 100644
index 0000000..6d28e62
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+#include "utils/CallbackUtils.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerCallbackTest : public LayerTransactionTest {
+public:
+ virtual sp<SurfaceControl> createBufferStateLayer() {
+ return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
+ }
+
+ static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+ const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
+ bool setBackgroundColor = false) {
+ if (layer) {
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ if (setBuffer) {
+ int err = getBuffer(&buffer, &fence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transaction.setBuffer(layer, buffer);
+ transaction.setAcquireFence(layer, fence);
+ }
+
+ if (setBackgroundColor) {
+ transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+ ui::Dataspace::UNKNOWN);
+ }
+ }
+
+ transaction.addTransactionCompletedCallback(callbackHelper->function,
+ callbackHelper->getContext());
+ return NO_ERROR;
+ }
+
+ static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState = false) {
+ CallbackData callbackData;
+ ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
+
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ static void waitForCallbacks(CallbackHelper& helper,
+ const std::vector<ExpectedResult>& expectedResults,
+ bool finalState = false) {
+ for (const auto& expectedResult : expectedResults) {
+ waitForCallback(helper, expectedResult);
+ }
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+};
+
+TEST_F(LayerCallbackTest, BufferColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferNoColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, false, false);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, BufferNoColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true, false);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoStateChange) {
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, OffScreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeBufferNoColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeNoBufferColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+TEST_F(LayerCallbackTest, Merge_SameCallback) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction1, &callback, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ ExpectedResult expected;
+
+ if (i == 0) {
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ } else {
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ }
+
+ transaction.apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ if (i == 0) {
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ } else {
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
+ : ExpectedResult::Transaction::NOT_PRESENTED,
+ layer,
+ (i == 0) ? ExpectedResult::Buffer::ACQUIRED
+ : ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ err = fillTransaction(transaction1, &callback1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ err = fillTransaction(transaction1, &callback1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::UNKNOWN);
+
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ // Normal call to set up test
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+
+ // Test
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+
+ err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ // Normal call to set up test
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expectedResult;
+ expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
+
+ // Test
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+
+ err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(time);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms after the first frame
+ time += (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ expected2.addExpectedPresentTime(time);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms before the previous frame
+ time -= (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the past
+ nsecs_t time = systemTime() - (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(systemTime());
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
new file mode 100644
index 0000000..83e5060
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -0,0 +1,1864 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <gui/BufferItemConsumer.h>
+#include <ui/Transform.h>
+#include <thread>
+#include "TransactionTestHarnesses.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerRenderTypeTransactionTest : public LayerTransactionTest,
+ public ::testing::WithParamInterface<RenderPath> {
+public:
+ LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
+ void setRelativeZBasicHelper(uint32_t layerType);
+ void setRelativeZGroupHelper(uint32_t layerType);
+ void setAlphaBasicHelper(uint32_t layerType);
+ void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
+ Color finalColor);
+
+protected:
+ LayerRenderPathTestHarness mHarness;
+};
+
+INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("default position");
+ const Rect rect(0, 0, 32, 32);
+ auto shot = getScreenCapture();
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ Transaction().setPosition(layer, 5, 10).apply();
+ {
+ SCOPED_TRACE("new position");
+ const Rect rect(5, 10, 37, 42);
+ auto shot = getScreenCapture();
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // GPU composition requires only 4 bits of subpixel precision during rasterization
+ // XXX GPU composition does not match HWC composition due to precision
+ // loss (b/69315223)
+ const float epsilon = 1.0f / 16.0f;
+ Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
+ {
+ SCOPED_TRACE("rounding down");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
+ {
+ SCOPED_TRACE("rounding up");
+ getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setPosition(layer, -32, -32).apply();
+ {
+ SCOPED_TRACE("negative coordinates");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+
+ Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
+ {
+ SCOPED_TRACE("positive coordinates");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // partially out of bounds
+ Transaction().setPosition(layer, -30, -30).apply();
+ {
+ SCOPED_TRACE("negative coordinates");
+ getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
+ }
+
+ Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
+ {
+ SCOPED_TRACE("positive coordinates");
+ getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
+ mDisplayHeight),
+ Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setPosition is applied immediately by default, with or without resize
+ // pending
+ Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
+ {
+ SCOPED_TRACE("resize pending");
+ auto shot = getScreenCapture();
+ const Rect rect(5, 10, 37, 42);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+ {
+ SCOPED_TRACE("resize applied");
+ getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setSize(layer, 64, 64).apply();
+ {
+ SCOPED_TRACE("resize pending");
+ auto shot = getScreenCapture();
+ const Rect rect(0, 0, 32, 32);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+ {
+ SCOPED_TRACE("resize applied");
+ auto shot = getScreenCapture();
+ const Rect rect(0, 0, 64, 64);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
+ Transaction()
+ .setSize(layer, 64, 64)
+ .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) {
+ uint32_t transformHint = ui::Transform::ROT_INVALID;
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr, &transformHint));
+ ASSERT_NE(ui::Transform::ROT_INVALID, transformHint);
+}
+
+void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
+
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ Transaction()
+ .setPosition(layerG, 16, 16)
+ .setRelativeLayer(layerG, layerR->getHandle(), 1)
+ .apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ Transaction()
+ .setFrame(layerR, Rect(0, 0, 32, 32))
+ .setFrame(layerG, Rect(16, 16, 48, 48))
+ .setRelativeLayer(layerG, layerR->getHandle(), 1)
+ .apply();
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+ {
+ SCOPED_TRACE("layerG above");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+ shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
+ }
+
+ Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
+ {
+ SCOPED_TRACE("layerG below");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ sp<SurfaceControl> layerB;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32));
+
+ // layerR = 0, layerG = layerR + 3, layerB = 2
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ Transaction()
+ .setPosition(layerG, 8, 8)
+ .setRelativeLayer(layerG, layerR->getHandle(), 3)
+ .setPosition(layerB, 16, 16)
+ .setLayer(layerB, mLayerZBase + 2)
+ .apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ Transaction()
+ .setFrame(layerR, Rect(0, 0, 32, 32))
+ .setFrame(layerG, Rect(8, 8, 40, 40))
+ .setRelativeLayer(layerG, layerR->getHandle(), 3)
+ .setFrame(layerB, Rect(16, 16, 48, 48))
+ .setLayer(layerB, mLayerZBase + 2)
+ .apply();
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+
+ {
+ SCOPED_TRACE("(layerR < layerG) < layerB");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+ shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
+ shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+ }
+
+ // layerR = 4, layerG = layerR + 3, layerB = 2
+ Transaction().setLayer(layerR, mLayerZBase + 4).apply();
+ {
+ SCOPED_TRACE("layerB < (layerR < layerG)");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+ shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
+ shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+ }
+
+ // layerR = 4, layerG = layerR - 3, layerB = 2
+ Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
+ {
+ SCOPED_TRACE("layerB < (layerG < layerR)");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
+ shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+ }
+
+ // restore to absolute z
+ // layerR = 4, layerG = 0, layerB = 2
+ Transaction().setLayer(layerG, mLayerZBase).apply();
+ {
+ SCOPED_TRACE("layerG < layerB < layerR");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
+ }
+
+ // layerR should not affect layerG anymore
+ // layerR = 1, layerG = 0, layerB = 2
+ Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+ {
+ SCOPED_TRACE("layerG < layerR < layerB");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+ shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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 = getBufferQueueLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::RED));
+ // setTransparentRegionHint always applies to the following buffer
+ Transaction().setTransparentRegionHint(layer, Region(top)).apply();
+ ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
+ {
+ SCOPED_TRACE("top transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::RED);
+ }
+
+ Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+ {
+ SCOPED_TRACE("transparent region hint pending");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::RED);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
+ {
+ SCOPED_TRACE("bottom transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::RED);
+ shot->expectColor(bottom, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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(
+ TransactionUtils::fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::RED));
+ Transaction()
+ .setTransparentRegionHint(layer, Region(top))
+ .setBuffer(layer, buffer)
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .apply();
+ {
+ SCOPED_TRACE("top transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::RED);
+ }
+
+ Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+ {
+ SCOPED_TRACE("transparent region hint intermediate");
+ auto shot = getScreenCapture();
+ 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(TransactionUtils::fillGraphicBufferColor(buffer, top, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
+ Transaction().setBuffer(layer, buffer).apply();
+ {
+ SCOPED_TRACE("bottom transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::RED);
+ shot->expectColor(bottom, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layerTransparent;
+ sp<SurfaceControl> layerR;
+ ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+
+ // check that transparent region hint is bound by the layer size
+ Transaction()
+ .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
+ .setPosition(layerR, 16, 16)
+ .setLayer(layerR, mLayerZBase + 1)
+ .apply();
+ ASSERT_NO_FATAL_FAILURE(
+ fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
+ sp<SurfaceControl> layerTransparent;
+ sp<SurfaceControl> layerR;
+ ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(
+ layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ // check that transparent region hint is bound by the layer size
+ Transaction()
+ .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
+ .setFrame(layerR, Rect(16, 16, 48, 48))
+ .setLayer(layerR, mLayerZBase + 1)
+ .apply();
+ ASSERT_NO_FATAL_FAILURE(
+ fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
+ sp<SurfaceControl> layer1;
+ sp<SurfaceControl> layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32));
+
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ Transaction()
+ .setAlpha(layer1, 0.25f)
+ .setAlpha(layer2, 0.75f)
+ .setPosition(layer2, 16, 0)
+ .setLayer(layer2, mLayerZBase + 1)
+ .apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ Transaction()
+ .setAlpha(layer1, 0.25f)
+ .setAlpha(layer2, 0.75f)
+ .setFrame(layer1, Rect(0, 0, 32, 32))
+ .setFrame(layer2, Rect(16, 0, 48, 32))
+ .setLayer(layer2, mLayerZBase + 1)
+ .apply();
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+ {
+ auto shot = getScreenCapture();
+ uint8_t r = 16; // 64 * 0.25f
+ uint8_t g = 48; // 64 * 0.75f
+ shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
+ shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255});
+
+ r /= 4; // r * (1.0f - 0.75f)
+ shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255});
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
+ sp<SurfaceControl> bufferLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
+
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+ const Color expected = {15, 51, 85, 255};
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+ Transaction().setColor(colorLayer, color).apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ }
+}
+
+// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
+// BLUE: prior background color
+// GREEN: final background color
+// BLACK: no color or fill
+void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
+ bool bufferFill, float alpha,
+ Color finalColor) {
+ sp<SurfaceControl> layer;
+ int32_t width = 500;
+ int32_t height = 500;
+
+ Color fillColor = Color::RED;
+ Color priorBgColor = Color::BLUE;
+ Color expectedColor = Color::BLACK;
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceEffect:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
+ Transaction()
+ .setCrop_legacy(layer, Rect(0, 0, width, height))
+ .setColor(layer, half3(1.0f, 0, 0))
+ .apply();
+ expectedColor = fillColor;
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
+ break;
+ default:
+ GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
+ return;
+ }
+
+ if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) {
+ Transaction()
+ .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
+ .apply();
+ if (!bufferFill) {
+ expectedColor = priorBgColor;
+ }
+ }
+
+ {
+ SCOPED_TRACE("default before setting background color layer");
+ screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
+ }
+ Transaction()
+ .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
+ .apply();
+
+ {
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, width, height), finalColor);
+ shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setColor(colorLayer, half3(2.0f, 0.0f, 0.0f))
+ .apply();
+
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+// An invalid color will not render a color and the layer will not be visible.
+TEST_P(LayerRenderTypeTransactionTest, SetInvalidColor) {
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setColor(colorLayer, half3(1.0f, -1.0f, 0.5f))
+ .apply();
+
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
+ sp<SurfaceControl> bufferLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+ Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+
+ const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+ const float alpha = 0.25f;
+ const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+ Transaction()
+ .setColor(colorLayer, color)
+ .setAlpha(colorLayer, alpha)
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
+ sp<SurfaceControl> bufferLayer;
+ sp<SurfaceControl> parentLayer;
+ 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(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+ Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+ const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+ const float alpha = 0.25f;
+ const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+ // this is handwavy, but the precision loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+ Transaction()
+ .reparent(colorLayer, parentLayer->getHandle())
+ .setColor(colorLayer, color)
+ .setAlpha(parentLayer, alpha)
+ .setLayer(parentLayer, mLayerZBase + 1)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(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();
+ {
+ SCOPED_TRACE("IDENTITY");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
+ {
+ SCOPED_TRACE("FLIP_H");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
+ Color::WHITE, Color::BLUE);
+ }
+
+ Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
+ {
+ SCOPED_TRACE("FLIP_V");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
+ Color::RED, Color::GREEN);
+ }
+
+ Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
+ {
+ SCOPED_TRACE("ROT_90");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
+ Color::WHITE, Color::GREEN);
+ }
+
+ Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
+ {
+ SCOPED_TRACE("SCALE");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_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()
+ .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .apply();
+ {
+ SCOPED_TRACE("IDENTITY");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
+ {
+ SCOPED_TRACE("FLIP_H");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
+ {
+ SCOPED_TRACE("FLIP_V");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
+ {
+ SCOPED_TRACE("ROT_90");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
+ {
+ SCOPED_TRACE("SCALE");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(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;
+ Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
+
+ auto shot = getScreenCapture();
+ // check a 8x8 region inside each color
+ auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
+ const int32_t halfL = 4;
+ return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL);
+ };
+ const int32_t unit = int32_t(trans / 2);
+ shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED);
+ shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN);
+ shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE);
+ shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(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 = getScreenCapture();
+ const Rect rect(0, 0, 32, 32);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+ {
+ SCOPED_TRACE("resize applied");
+ const Rect rect(0, 0, 128, 128);
+ getScreenCapture()->expectColor(rect, Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
+ Transaction()
+ .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+ .setSize(layer, 64, 64)
+ .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(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
+ // (b/69315456)
+ Transaction()
+ .setSize(layer, 64, 16)
+ .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+ .apply();
+ {
+ SCOPED_TRACE("SCALE_TO_WINDOW");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+ const Rect crop(8, 8, 24, 24);
+
+ Transaction().setCrop_legacy(layer, crop).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(crop, Color::RED);
+ shot->expectBorder(crop, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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 = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("empty rect");
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ {
+ SCOPED_TRACE("negative rect");
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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();
+ getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ }
+
+ {
+ SCOPED_TRACE("negative rect");
+ Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
+
+ Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply();
+
+ Transaction().setBuffer(layer, buffer).apply();
+
+ // Partially out of bounds in the negative (upper left) direction
+ Transaction().setCrop(layer, Rect(-128, -128, 32, 16)).apply();
+ {
+ SCOPED_TRACE("out of bounds, negative (upper left) direction");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ }
+
+ // Partially out of bounds in the positive (lower right) direction
+ Transaction().setCrop(layer, Rect(0, 16, 128, 128)).apply();
+ {
+ SCOPED_TRACE("out of bounds, positive (lower right) direction");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ }
+
+ // Fully out of buffer space bounds
+ Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
+ {
+ SCOPED_TRACE("Fully out of bounds");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE);
+ shot->expectColor(Rect(0, 16, 64, 64), Color::RED);
+ shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ const Point position(32, 32);
+ const Rect crop(8, 8, 24, 24);
+ Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(crop + position, Color::RED);
+ shot->expectBorder(crop + position, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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 Rect frame(32, 32, 64, 64);
+ const Rect crop(8, 8, 24, 24);
+ Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(frame, Color::RED);
+ shot->expectBorder(frame, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // crop_legacy is affected by matrix
+ Transaction()
+ .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+ .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+ .apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ 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();
+ {
+ SCOPED_TRACE("resize pending");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
+ shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
+ {
+ SCOPED_TRACE("resize applied");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+ shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_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 frame(8, 8, 24, 24);
+
+ Transaction().setFrame(layer, frame).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(frame, Color::RED);
+ shot->expectBorder(frame, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_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().setFrame(layer, Rect(8, 8, 8, 8)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ {
+ SCOPED_TRACE("negative rect");
+ Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
+
+ // A parentless layer will default to a frame with the same size as the buffer
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
+ sp<SurfaceControl> parent, child;
+ ASSERT_NO_FATAL_FAILURE(
+ parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+ Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+ ASSERT_NO_FATAL_FAILURE(
+ child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+ Transaction().reparent(child, parent->getHandle()).apply();
+
+ // A layer will default to the frame of its parent
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
+ sp<SurfaceControl> parent, child;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
+
+ ASSERT_NO_FATAL_FAILURE(
+ child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+ Transaction().reparent(child, parent->getHandle()).apply();
+
+ // A layer will default to the frame of its parent
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_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().setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ std::this_thread::sleep_for(500ms);
+
+ Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
+ sp<SurfaceControl> parent, child;
+ ASSERT_NO_FATAL_FAILURE(
+ parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(
+ child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ Transaction().reparent(child, parent->getHandle()).apply();
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+ Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+ Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
+ shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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 = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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 = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 2");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 3");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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));
+
+ Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
+ {
+ SCOPED_TRACE("set layer 1 buffer red");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
+
+ Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
+ {
+ SCOPED_TRACE("set layer 2 buffer blue");
+ auto shot = getScreenCapture();
+ 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 = getScreenCapture();
+ 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 = getScreenCapture();
+ 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_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 10> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 70> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 65> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+ if (idx == 0) {
+ buffers[0].clear();
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
+ .apply();
+
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+ Color::GREEN, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
+ .apply();
+
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+ Color::BLUE, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
+ .apply();
+
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+ Color::GREEN, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ Transaction transaction;
+ 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");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ sp<Fence> fence;
+ if (getBuffer(nullptr, &fence) != NO_ERROR) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+
+ status_t status = fence->wait(1000);
+ ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
+ std::this_thread::sleep_for(200ms);
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_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");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ sp<Fence> fence = Fence::NO_FENCE;
+
+ Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ HdrMetadata hdrMetadata;
+ hdrMetadata.validTypes = 0;
+ Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Region region;
+ region.set(32, 32);
+ Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, 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");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+ half3 expected = color;
+ mat3 matrix;
+ matrix[0][0] = 0.3;
+ matrix[1][0] = 0.59;
+ matrix[2][0] = 0.11;
+ matrix[0][1] = 0.3;
+ matrix[1][1] = 0.59;
+ matrix[2][1] = 0.11;
+ matrix[0][2] = 0.3;
+ matrix[1][2] = 0.59;
+ matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
+ Transaction().setColor(colorLayer, color).setColorTransform(colorLayer, matrix, vec3()).apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
+ sp<SurfaceControl> parentLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer));
+ ASSERT_NO_FATAL_FAILURE(
+ colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
+
+ Transaction()
+ .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(parentLayer, mLayerZBase + 1)
+ .apply();
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+ half3 expected = color;
+ mat3 matrix;
+ matrix[0][0] = 0.3;
+ matrix[1][0] = 0.59;
+ matrix[2][0] = 0.11;
+ matrix[0][1] = 0.3;
+ matrix[1][1] = 0.59;
+ matrix[2][1] = 0.11;
+ matrix[0][2] = 0.3;
+ matrix[1][2] = 0.59;
+ matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
+ Transaction()
+ .setColor(colorLayer, color)
+ .setColorTransform(parentLayer, matrix, vec3())
+ .apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
+ sp<SurfaceControl> parentLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer));
+ ASSERT_NO_FATAL_FAILURE(
+ colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
+
+ Transaction()
+ .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(parentLayer, mLayerZBase + 1)
+ .apply();
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+ half3 expected = color;
+ mat3 matrixChild;
+ matrixChild[0][0] = 0.3;
+ matrixChild[1][0] = 0.59;
+ matrixChild[2][0] = 0.11;
+ matrixChild[0][1] = 0.3;
+ matrixChild[1][1] = 0.59;
+ matrixChild[2][1] = 0.11;
+ matrixChild[0][2] = 0.3;
+ matrixChild[1][2] = 0.59;
+ matrixChild[2][2] = 0.11;
+ mat3 matrixParent;
+ matrixParent[0][0] = 0.2;
+ matrixParent[1][0] = 0.4;
+ matrixParent[2][0] = 0.10;
+ matrixParent[0][1] = 0.2;
+ matrixParent[1][1] = 0.4;
+ matrixParent[2][1] = 0.10;
+ matrixParent[0][2] = 0.2;
+ matrixParent[1][2] = 0.4;
+ matrixParent[2][2] = 0.10;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrixChild);
+ ColorTransformHelper::applyMatrix(expected, matrixParent);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
+ Transaction()
+ .setColor(colorLayer, color)
+ .setColorTransform(parentLayer, matrixParent, vec3())
+ .setColorTransform(colorLayer, matrixChild, vec3())
+ .apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ }
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
new file mode 100644
index 0000000..f3e11d8
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2019 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 <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayConfig.h>
+
+#include "BufferGenerator.h"
+#include "utils/ScreenshotUtils.h"
+#include "utils/TransactionUtils.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTransactionTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ mClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
+
+ ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
+ }
+
+ virtual void TearDown() {
+ mBlackBgSurface = 0;
+ mClient->dispose();
+ mClient = 0;
+ }
+
+ virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0, SurfaceControl* parent = nullptr,
+ uint32_t* outTransformHint = nullptr,
+ PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
+ auto layer =
+ createSurface(client, name, width, height, format, flags, parent, outTransformHint);
+
+ Transaction t;
+ t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
+
+ status_t error = t.apply();
+ if (error != NO_ERROR) {
+ ADD_FAILURE() << "failed to initialize SurfaceControl";
+ layer.clear();
+ }
+
+ return layer;
+ }
+
+ virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t flags,
+ SurfaceControl* parent = nullptr,
+ uint32_t* outTransformHint = nullptr) {
+ auto layer = client->createSurface(String8(name), width, height, format, flags, parent,
+ LayerMetadata(), outTransformHint);
+ EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
+ return layer;
+ }
+
+ virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0, SurfaceControl* parent = nullptr,
+ uint32_t* outTransformHint = nullptr,
+ PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
+ return createLayer(mClient, name, width, height, flags, parent, outTransformHint, format);
+ }
+
+ sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
+ SurfaceControl* parent = nullptr) {
+ auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect, parent);
+ asTransaction([&](Transaction& t) {
+ t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
+ t.setAlpha(colorLayer, color.a / 255.0f);
+ });
+ return colorLayer;
+ }
+
+ ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
+ // wait for previous transactions (such as setSize) to complete
+ Transaction().apply(true);
+
+ ANativeWindow_Buffer buffer = {};
+ EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
+
+ return buffer;
+ }
+
+ void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
+ ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+
+ // wait for the newly posted buffer to be latched
+ waitForLayerBuffers();
+ }
+
+ virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+ int32_t bufferWidth, int32_t bufferHeight) {
+ ANativeWindow_Buffer buffer;
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ TransactionUtils::fillANativeWindowBufferColor(buffer,
+ Rect(0, 0, bufferWidth, bufferHeight),
+ color);
+ postBufferQueueLayerBuffer(layer);
+ }
+
+ 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");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight),
+ color);
+ Transaction().setBuffer(layer, buffer).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 = getBufferQueueLayerBuffer(layer));
+ ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
+
+ const int32_t halfW = bufferWidth / 2;
+ const int32_t halfH = bufferHeight / 2;
+ TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+ TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
+ topRight);
+ TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
+ bottomLeft);
+ TransactionUtils::fillANativeWindowBufferColor(buffer,
+ Rect(halfW, halfH, bufferWidth,
+ bufferHeight),
+ bottomRight);
+
+ 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;
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
+ topRight);
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
+ bottomLeft);
+ TransactionUtils::fillGraphicBufferColor(buffer,
+ Rect(halfW, halfH, bufferWidth, bufferHeight),
+ bottomRight);
+
+ Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
+ }
+
+ std::unique_ptr<ScreenCapture> screenshot() {
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ return screenshot;
+ }
+
+ void asTransaction(const std::function<void(Transaction&)>& exec) {
+ Transaction t;
+ exec(t);
+ t.apply(true);
+ }
+
+ static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+ static BufferGenerator bufferGenerator;
+ return bufferGenerator.get(outBuffer, outFence);
+ }
+
+ sp<SurfaceComposerClient> mClient;
+
+ sp<IBinder> mDisplay;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
+ uint32_t mDisplayLayerStack;
+ Rect mDisplayRect = Rect::INVALID_RECT;
+
+ // leave room for ~256 layers
+ const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
+
+ sp<SurfaceControl> mBlackBgSurface;
+ bool mColorManagementUsed;
+
+private:
+ void SetUpDisplay() {
+ mDisplay = mClient->getInternalDisplayToken();
+ ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
+
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
+ mDisplayRect = Rect(config.resolution);
+ mDisplayWidth = mDisplayRect.getWidth();
+ mDisplayHeight = mDisplayRect.getHeight();
+
+ // After a new buffer is queued, SurfaceFlinger is notified and will
+ // latch the new buffer on next vsync. Let's heuristically wait for 3
+ // vsyncs.
+ mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
+
+ mDisplayLayerStack = 0;
+
+ mBlackBgSurface =
+ createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
+
+ // set layer stack (b/68888219)
+ Transaction t;
+ t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
+ t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
+ t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
+ t.setColor(mBlackBgSurface, half3{0, 0, 0});
+ t.setLayer(mBlackBgSurface, mLayerZBase);
+ t.apply();
+ }
+
+ void waitForLayerBuffers() {
+ // Request an empty transaction to get applied synchronously to ensure the buffer is
+ // latched.
+ Transaction().apply(true);
+ usleep(mBufferPostDelay);
+ }
+
+ int32_t mBufferPostDelay;
+
+ friend class LayerRenderPathTestHarness;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
new file mode 100644
index 0000000..1f8f7ed
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <private/android_filesystem_config.h>
+#include <thread>
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<GraphicBuffer> outBuffer;
+ Transaction()
+ .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+ .apply(true);
+ ASSERT_EQ(PERMISSION_DENIED,
+ composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ UIDFaker f(AID_SYSTEM);
+
+ // By default the system can capture screenshots with secure layers but they
+ // will be blacked out
+ ASSERT_EQ(NO_ERROR, composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ {
+ SCOPED_TRACE("as system");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
+ // to receive them...we are expected to take care with the results.
+ bool outCapturedSecureLayers;
+ ASSERT_EQ(NO_ERROR,
+ composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
+ ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
+ 0, false, ui::ROTATION_0, true));
+ ASSERT_EQ(true, outCapturedSecureLayers);
+ ScreenCapture sc(outBuffer);
+ sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+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, 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();
+}
+
+TEST_F(LayerTransactionTest, ReparentToSelf) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+ Transaction().reparent(layer, layer->getHandle()).apply();
+
+ {
+ // We expect the transaction to be silently dropped, but for SurfaceFlinger
+ // to still be functioning.
+ SCOPED_TRACE("after reparent to self");
+ const Rect rect(0, 0, 32, 32);
+ auto shot = screenshot();
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+}
+
+// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
+// the dropped buffer's damage region into the next buffer's damage region. If
+// we don't do this, we'll report an incorrect damage region to hardware
+// composer, resulting in broken rendering. This test checks the BufferQueue
+// case.
+//
+// Unfortunately, we don't currently have a way to inspect the damage region
+// SurfaceFlinger sends to hardware composer from a test, so this test requires
+// the dev to manually watch the device's screen during the test to spot broken
+// rendering. Because the results can't be automatically verified, this test is
+// marked disabled.
+TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
+ const int width = mDisplayWidth;
+ const int height = mDisplayHeight;
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ const auto producer = layer->getIGraphicBufferProducer();
+ const sp<IProducerListener> stubListener(new StubProducerListener);
+ IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
+ ASSERT_EQ(OK, producer->connect(stubListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
+
+ std::map<int, sp<GraphicBuffer>> slotMap;
+ auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
+ ASSERT_NE(nullptr, buf);
+ const auto iter = slotMap.find(slot);
+ ASSERT_NE(slotMap.end(), iter);
+ *buf = iter->second;
+ };
+
+ auto dequeue = [&](int* outSlot) {
+ ASSERT_NE(nullptr, outSlot);
+ *outSlot = -1;
+ int slot;
+ sp<Fence> fence;
+ uint64_t age;
+ FrameEventHistoryDelta timestamps;
+ const status_t dequeueResult =
+ producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &age, ×tamps);
+ if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+ sp<GraphicBuffer> newBuf;
+ ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
+ ASSERT_NE(nullptr, newBuf.get());
+ slotMap[slot] = newBuf;
+ } else {
+ ASSERT_EQ(OK, dequeueResult);
+ }
+ *outSlot = slot;
+ };
+
+ auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
+ IGraphicBufferProducer::QueueBufferInput input(
+ /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
+ /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+ /*transform=*/0, Fence::NO_FENCE);
+ input.setSurfaceDamage(damage);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
+ };
+
+ auto fillAndPostBuffers = [&](const Color& color) {
+ int slot1;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
+ int slot2;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
+
+ sp<GraphicBuffer> buf1;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
+ sp<GraphicBuffer> buf2;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
+ TransactionUtils::fillGraphicBufferColor(buf1, Rect(width, height), color);
+ TransactionUtils::fillGraphicBufferColor(buf2, Rect(width, height), color);
+
+ const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
+ ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
+ ASSERT_NO_FATAL_FAILURE(
+ queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
+ displayTime));
+ };
+
+ const auto startTime = systemTime();
+ const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
+ int colorIndex = 0;
+ while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
+ ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
+ std::this_thread::sleep_for(1s);
+ }
+
+ ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
new file mode 100644
index 0000000..7d4314f
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <cutils/properties.h>
+#include <gui/BufferItemConsumer.h>
+#include "TransactionTestHarnesses.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTypeAndRenderTypeTransactionTest
+ : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
+public:
+ LayerTypeAndRenderTypeTransactionTest()
+ : LayerTypeTransactionHarness(std::get<0>(GetParam())),
+ mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ return mRenderPathHarness.getScreenCapture();
+ }
+
+protected:
+ LayerRenderPathTestHarness mRenderPathHarness;
+};
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+INSTANTIATE_TEST_CASE_P(
+ LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
+ ::testing::Combine(
+ ::testing::Values(
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
+ // cannot test robustness against invalid sizes (zero or really huge)
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+ Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+ {
+ SCOPED_TRACE("layerR");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ Transaction().setLayer(layerG, mLayerZBase + 2).apply();
+ {
+ SCOPED_TRACE("layerG");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+ Transaction()
+ .setPosition(layerG, 16, 16)
+ .setRelativeLayer(layerG, layerR->getHandle(), 1)
+ .apply();
+
+ Transaction().reparent(layerG, nullptr).apply();
+
+ // layerG should have been removed
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
+ {
+ SCOPED_TRACE("layer hidden");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+
+ Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
+ {
+ SCOPED_TRACE("layer shown");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+ Transaction()
+ .setLayer(layerR, mLayerZBase + 1)
+ .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+ .apply();
+ {
+ SCOPED_TRACE("layerR opaque");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
+ }
+
+ Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
+ {
+ SCOPED_TRACE("layerR translucent");
+ const uint8_t g = uint8_t(255 - translucentRed.a);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer);
+ Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+ 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, 32, 32));
+
+ Transaction()
+ .reparent(layerR, parent->getHandle())
+ .reparent(layerG, parent->getHandle())
+ .apply();
+ Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
+ {
+ SCOPED_TRACE("layerR");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ Transaction().setLayer(layerR, -3).apply();
+ {
+ SCOPED_TRACE("layerG");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
+
+ Transaction().setAlpha(layer, 2.0f).apply();
+ {
+ SCOPED_TRACE("clamped to 1.0f");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
+ }
+
+ Transaction().setAlpha(layer, -1.0f).apply();
+ {
+ SCOPED_TRACE("clamped to 0.0f");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
+ sp<SurfaceControl> layer;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
+
+ if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+ Transaction()
+ .setCornerRadius(layer, cornerRadius)
+ .setCrop_legacy(layer, Rect(0, 0, size, size))
+ .apply();
+ } else {
+ Transaction()
+ .setCornerRadius(layer, cornerRadius)
+ .setFrame(layer, Rect(0, 0, size, size))
+ .apply();
+ }
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ // Transparent corners
+ shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
+ shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+ shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
+ // Solid center
+ shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+ size / 2 + testArea / 2, size / 2 + testArea / 2),
+ Color::RED);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
+ ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+ auto transaction = Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCrop_legacy(parent, Rect(0, 0, size, size))
+ .reparent(child, parent->getHandle())
+ .setPosition(child, 0, size)
+ // Rotate by half PI
+ .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f);
+ if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+ transaction.setCrop_legacy(parent, Rect(0, 0, size, size));
+ } else {
+ transaction.setFrame(parent, Rect(0, 0, size, size));
+ }
+ transaction.apply();
+
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ // Edges are transparent
+ shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
+ shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom - testArea), Color::BLACK);
+ shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
+ // Solid center
+ shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+ size / 2 + testArea / 2, size / 2 + testArea / 2),
+ Color::GREEN);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
+ ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
+
+ if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCrop_legacy(parent, Rect(0, 0, size, size))
+ .reparent(child, parent->getHandle())
+ .setPosition(child, 0, size / 2)
+ .apply();
+ } else {
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setFrame(parent, Rect(0, 0, size, size))
+ .reparent(child, parent->getHandle())
+ .setFrame(child, Rect(0, size / 2, size, size))
+ .apply();
+ }
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ // Top edge of child should not have rounded corners because it's translated in the parent
+ shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
+ Color::GREEN);
+ // But bottom edges should have been clipped according to parent bounds
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+ shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadius) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.surface_flinger.supports_background_blur", value, "0");
+ if (!atoi(value)) {
+ // This device doesn't support blurs, no-op.
+ return;
+ }
+
+ auto size = 256;
+ auto center = size / 2;
+ auto blurRadius = 50;
+
+ sp<SurfaceControl> backgroundLayer;
+ ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
+
+ sp<SurfaceControl> leftLayer;
+ ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
+
+ sp<SurfaceControl> blurLayer;
+ ASSERT_NO_FATAL_FAILURE(blurLayer = createLayer("blur", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(blurLayer, Color::TRANSPARENT, size, size));
+
+ Transaction().setBackgroundBlurRadius(blurLayer, blurRadius).apply();
+
+ auto shot = getScreenCapture();
+ // Edges are mixed
+ shot->expectColor(Rect(center - 1, center - 5, center, center + 5), Color{150, 150, 0, 255},
+ 50 /* tolerance */);
+ shot->expectColor(Rect(center, center - 5, center + 1, center + 5), Color{150, 150, 0, 255},
+ 50 /* tolerance */);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusOnMultipleLayers) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.surface_flinger.supports_background_blur", value, "0");
+ if (!atoi(value)) {
+ // This device doesn't support blurs, no-op.
+ return;
+ }
+
+ auto size = 256;
+ auto center = size / 2;
+ auto blurRadius = 50;
+
+ sp<SurfaceControl> backgroundLayer;
+ ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
+
+ sp<SurfaceControl> leftLayer;
+ ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
+
+ sp<SurfaceControl> blurLayer1;
+ auto centralSquareSize = size / 2;
+ ASSERT_NO_FATAL_FAILURE(blurLayer1 =
+ createLayer("blur1", centralSquareSize, centralSquareSize));
+ ASSERT_NO_FATAL_FAILURE(
+ fillLayerColor(blurLayer1, Color::BLUE, centralSquareSize, centralSquareSize));
+
+ sp<SurfaceControl> blurLayer2;
+ ASSERT_NO_FATAL_FAILURE(blurLayer2 = createLayer("blur2", size, size));
+ ASSERT_NO_FATAL_FAILURE(
+ fillLayerColor(blurLayer2, Color::TRANSPARENT, centralSquareSize, centralSquareSize));
+
+ Transaction()
+ .setBackgroundBlurRadius(blurLayer1, blurRadius)
+ .setBackgroundBlurRadius(blurLayer2, blurRadius)
+ .apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(center - 5, center - 5, center, center), Color{100, 100, 100, 255},
+ 40 /* tolerance */);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
+ sp<SurfaceControl> bufferLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
+
+ // color is ignored
+ Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
+ {
+ SCOPED_TRACE("non-existing layer stack");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+
+ Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
+ {
+ SCOPED_TRACE("original layer stack");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) {
+ int32_t width = 100;
+ int32_t height = 100;
+ Rect crop = Rect(0, 0, width, height);
+
+ sp<SurfaceControl> behindLayer = createColorLayer("Behind layer", Color::RED);
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, 0, nullptr, nullptr,
+ PIXEL_FORMAT_RGBX_8888));
+
+ Transaction()
+ .setLayer(layer, INT32_MAX - 1)
+ .show(layer)
+ .setLayerStack(behindLayer, mDisplayLayerStack)
+ .setCrop_legacy(behindLayer, crop)
+ .setLayer(behindLayer, INT32_MAX - 2)
+ .show(behindLayer)
+ .apply();
+
+ sp<Surface> surface = layer->getSurface();
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
+
+ if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+ Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
+ } else {
+ Transaction().setBuffer(layer, buffer).apply();
+ }
+
+ {
+ SCOPED_TRACE("Buffer Opaque Format");
+ auto shot = screenshot();
+ shot->expectColor(crop, Color::BLACK);
+ }
+
+ buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
+
+ if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+ Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
+ } else {
+ Transaction().setBuffer(layer, buffer).apply();
+ }
+
+ {
+ SCOPED_TRACE("Buffer Transparent Format");
+ auto shot = screenshot();
+ shot->expectColor(crop, Color::RED);
+ }
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
new file mode 100644
index 0000000..84780ba
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <gui/BufferItemConsumer.h>
+#include "TransactionTestHarnesses.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<uint32_t> {
+public:
+ LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
+};
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+INSTANTIATE_TEST_CASE_P(
+ LayerTypeTransactionTests, LayerTypeTransactionTest,
+ ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
+
+TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer);
+ Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+ 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, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ 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, 32, 32));
+
+ Transaction().reparent(layerB, parent->getHandle()).apply();
+
+ // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
+ Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
+
+ std::unique_ptr<ScreenCapture> screenshot;
+ // only layerB is in this range
+ sp<IBinder> parentHandle = parent->getHandle();
+ ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
+ screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+}
+
+TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect);
+
+ sp<SurfaceControl> childLayer;
+ ASSERT_NO_FATAL_FAILURE(
+ childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect,
+ parent.get()));
+ Transaction()
+ .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
+ .setColor(parent, half3{0.0f, 0.0f, 0.0f})
+ .show(childLayer)
+ .show(parent)
+ .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
+ .apply();
+
+ Transaction()
+ .setRelativeLayer(childLayer, parent->getHandle(), -1)
+ .setLayer(childLayer, 1)
+ .apply();
+
+ {
+ SCOPED_TRACE("setLayer above");
+ // Set layer should get applied and place the child above.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
+ }
+
+ Transaction()
+ .setLayer(childLayer, 1)
+ .setRelativeLayer(childLayer, parent->getHandle(), -1)
+ .apply();
+
+ {
+ SCOPED_TRACE("setRelative below");
+ // Set relative layer should get applied and place the child below.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect);
+ sp<SurfaceControl> relativeParent =
+ LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect);
+
+ sp<SurfaceControl> childLayer;
+ ASSERT_NO_FATAL_FAILURE(
+ childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceEffect,
+ parent.get()));
+ Transaction()
+ .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
+ .setColor(parent, half3{0.0f, 0.0f, 0.0f})
+ .setColor(relativeParent, half3{0.0f, 1.0f, 0.0f})
+ .show(childLayer)
+ .show(parent)
+ .show(relativeParent)
+ .setLayer(parent, mLayerZBase - 1)
+ .setLayer(relativeParent, mLayerZBase)
+ .apply();
+
+ Transaction().setRelativeLayer(childLayer, relativeParent->getHandle(), 1).apply();
+
+ {
+ SCOPED_TRACE("setLayer above");
+ // Set layer should get applied and place the child above.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
+ }
+
+ Transaction().hide(relativeParent).apply();
+
+ {
+ SCOPED_TRACE("hide relative parent");
+ // The relative should no longer be visible.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<GraphicBuffer> outBuffer;
+ Transaction()
+ .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+ .apply(true);
+ ASSERT_EQ(PERMISSION_DENIED,
+ composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
+ ASSERT_EQ(NO_ERROR, composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+}
+TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+
+ sp<IBinder> handle = layer->getHandle();
+ ASSERT_TRUE(handle != nullptr);
+
+ FrameStats frameStats;
+ mClient->getLayerFrameStats(handle, &frameStats);
+
+ ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
new file mode 100644
index 0000000..cdd9d92
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -0,0 +1,1719 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerUpdateTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
+
+ // Background surface
+ mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
+ resolution.getHeight(), 0);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+ TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
+
+ // Foreground surface
+ mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0);
+
+ ASSERT_TRUE(mFGSurfaceControl != nullptr);
+ ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+
+ // Synchronization surface
+ mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0);
+ ASSERT_TRUE(mSyncSurfaceControl != nullptr);
+ ASSERT_TRUE(mSyncSurfaceControl->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+
+ t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
+
+ t.setLayer(mFGSurfaceControl, INT32_MAX - 1)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .show(mFGSurfaceControl);
+
+ t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
+ .setPosition(mSyncSurfaceControl, resolution.getWidth() - 2,
+ resolution.getHeight() - 2)
+ .show(mSyncSurfaceControl);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mBGSurfaceControl = 0;
+ mFGSurfaceControl = 0;
+ mSyncSurfaceControl = 0;
+ }
+
+ void waitForPostedBuffers() {
+ // Since the sync surface is in synchronous mode (i.e. double buffered)
+ // posting three buffers to it should ensure that at least two
+ // SurfaceFlinger::handlePageFlip calls have been made, which should
+ // guaranteed that a buffer posted to another Surface has been retired.
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ }
+
+ sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mFGSurfaceControl;
+
+ // This surface is used to ensure that the buffers posted to
+ // mFGSurfaceControl have been picked up by SurfaceFlinger.
+ sp<SurfaceControl> mSyncSurfaceControl;
+};
+
+TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ sp<SurfaceControl> relative = createLayer(String8("relativeTestSurface"), 10, 10, 0);
+ TransactionUtils::fillSurfaceRGBA8(relative, 10, 10, 10);
+ waitForPostedBuffers();
+
+ Transaction{}
+ .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
+ .setPosition(relative, 64, 64)
+ .apply();
+
+ {
+ // The relative should be on top of the FG control.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(64, 64, 10, 10, 10);
+ }
+ Transaction{}.detachChildren(mFGSurfaceControl).apply();
+
+ {
+ // Nothing should change at this point.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(64, 64, 10, 10, 10);
+ }
+
+ Transaction{}.hide(relative).apply();
+
+ {
+ // Ensure that the relative was actually hidden, rather than
+ // being left in the detached but visible state.
+ ScreenCapture::captureScreen(&sc);
+ sc->expectFGColor(64, 64);
+ }
+}
+
+class GeometryLatchingTest : public LayerUpdateTest {
+protected:
+ void EXPECT_INITIAL_STATE(const char* trace) {
+ SCOPED_TRACE(trace);
+ ScreenCapture::captureScreen(&sc);
+ // We find the leading edge of the FG surface.
+ sc->expectFGColor(127, 127);
+ sc->expectBGColor(128, 128);
+ }
+
+ void lockAndFillFGBuffer() {
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false);
+ }
+
+ void unlockFGBuffer() {
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ waitForPostedBuffers();
+ }
+
+ void completeFGResize() {
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+ }
+ void restoreInitialState() {
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 64, 64);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+ });
+
+ EXPECT_INITIAL_STATE("After restoring initial state");
+ }
+ std::unique_ptr<ScreenCapture> sc;
+};
+
+class CropLatchingTest : public GeometryLatchingTest {
+protected:
+ void EXPECT_CROPPED_STATE(const char* trace) {
+ SCOPED_TRACE(trace);
+ ScreenCapture::captureScreen(&sc);
+ // The edge should be moved back one pixel by our crop.
+ sc->expectFGColor(126, 126);
+ sc->expectBGColor(127, 127);
+ sc->expectBGColor(128, 128);
+ }
+
+ void EXPECT_RESIZE_STATE(const char* trace) {
+ SCOPED_TRACE(trace);
+ ScreenCapture::captureScreen(&sc);
+ // The FG is now resized too 128,128 at 64,64
+ sc->expectFGColor(64, 64);
+ sc->expectFGColor(191, 191);
+ sc->expectBGColor(192, 192);
+ }
+};
+
+TEST_F(LayerUpdateTest, DeferredTransactionTest) {
+ std::unique_ptr<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before anything");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->expectFGColor(96, 96);
+ sc->expectBGColor(160, 160);
+ }
+
+ // set up two deferred transactions on different frames
+ asTransaction([&](Transaction& t) {
+ t.setAlpha(mFGSurfaceControl, 0.75);
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+ });
+
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 128, 128);
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+ });
+
+ {
+ SCOPED_TRACE("before any trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->expectFGColor(96, 96);
+ sc->expectBGColor(160, 160);
+ }
+
+ // should trigger the first deferred transaction, but not the second one
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ {
+ SCOPED_TRACE("after first trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->checkPixel(96, 96, 162, 63, 96);
+ sc->expectBGColor(160, 160);
+ }
+
+ // should show up immediately since it's not deferred
+ asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
+
+ // trigger the second deferred transaction
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ {
+ SCOPED_TRACE("after second trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->expectBGColor(96, 96);
+ sc->expectFGColor(160, 160);
+ }
+}
+
+TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ sp<SurfaceControl> childNoBuffer =
+ createSurface(mClient, "Bufferless child", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> childBuffer = createSurface(mClient, "Buffered child", 20, 20,
+ PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
+ TransactionUtils::fillSurfaceRGBA8(childBuffer, 200, 200, 200);
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
+ .show(childNoBuffer)
+ .show(childBuffer)
+ .apply(true);
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectChildColor(73, 73);
+ sc->expectFGColor(74, 74);
+ }
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
+ .apply(true);
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectChildColor(73, 73);
+ sc->expectChildColor(74, 74);
+ }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactions) {
+ std::unique_ptr<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before move");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(0, 12);
+ sc->expectFGColor(75, 75);
+ sc->expectBGColor(145, 145);
+ }
+
+ Transaction t1, t2;
+ t1.setPosition(mFGSurfaceControl, 128, 128);
+ t2.setPosition(mFGSurfaceControl, 0, 0);
+ // We expect that the position update from t2 now
+ // overwrites the position update from t1.
+ t1.merge(std::move(t2));
+ t1.apply();
+
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectFGColor(1, 1);
+ }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactionFlags) {
+ Transaction().hide(mFGSurfaceControl).apply();
+ std::unique_ptr<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before merge");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(0, 12);
+ sc->expectBGColor(75, 75);
+ sc->expectBGColor(145, 145);
+ }
+
+ Transaction t1, t2;
+ t1.show(mFGSurfaceControl);
+ t2.setFlags(mFGSurfaceControl, 0 /* flags */, layer_state_t::eLayerSecure /* mask */);
+ t1.merge(std::move(t2));
+ t1.apply();
+
+ {
+ SCOPED_TRACE("after merge");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectFGColor(75, 75);
+ }
+}
+
+class ChildLayerTest : public LayerUpdateTest {
+protected:
+ void SetUp() override {
+ LayerUpdateTest::SetUp();
+ mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ SCOPED_TRACE("before anything");
+ mCapture = screenshot();
+ mCapture->expectChildColor(64, 64);
+ }
+ }
+ void TearDown() override {
+ LayerUpdateTest::TearDown();
+ mChild = 0;
+ }
+
+ sp<SurfaceControl> mChild;
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(ChildLayerTest, ChildLayerPositioning) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground should now be at 0, 0
+ mCapture->expectFGColor(0, 0);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(10, 10);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(20, 20);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerCropping) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(4, 4);
+ mCapture->expectBGColor(5, 5);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerConstraints) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 63, 63);
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(0, 0);
+ // Last pixel in foreground should now be the child.
+ mCapture->expectChildColor(63, 63);
+ // But the child should be constrained and the next pixel
+ // must be the background
+ mCapture->expectBGColor(64, 64);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerScaling) {
+ asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
+
+ // Find the boundary between the parent and child
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectFGColor(10, 10);
+ }
+
+ asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); });
+
+ // The boundary should be twice as far from the origin now.
+ // The pixels from the last test should all be child now
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ mCapture->expectChildColor(19, 19);
+ mCapture->expectFGColor(20, 20);
+ }
+}
+
+// A child with a scale transform should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 0, 0);
+ });
+
+ // Find the boundary between the parent and child.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectFGColor(10, 10);
+ }
+
+ asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
+
+ // The child should fill its parent bounds and be cropped by it.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerAlpha) {
+ TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
+ TransactionUtils::fillSurfaceRGBA8(mChild, 0, 254, 0);
+ waitForPostedBuffers();
+
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ // Unblended child color
+ mCapture->checkPixel(0, 0, 0, 254, 0);
+ }
+
+ asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); });
+
+ {
+ mCapture = screenshot();
+ // Child and BG blended.
+ mCapture->checkPixel(0, 0, 127, 127, 0);
+ }
+
+ asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); });
+
+ {
+ mCapture = screenshot();
+ // Child and BG blended.
+ mCapture->checkPixel(0, 0, 95, 64, 95);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentChildren) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ // In reparenting we should have exposed the entire foreground surface.
+ mCapture->expectFGColor(74, 74);
+ // And the child layer should now begin at 10, 10 (since the BG
+ // layer is at (0, 0)).
+ mCapture->expectBGColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
+ sp<SurfaceControl> mGrandChild =
+ createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+ {
+ SCOPED_TRACE("Grandchild visible");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 111, 111, 111);
+ }
+
+ Transaction().reparent(mChild, nullptr).apply();
+ mChild.clear();
+
+ {
+ SCOPED_TRACE("After destroying child");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectFGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) { t.reparent(mGrandChild, mFGSurfaceControl->getHandle()); });
+
+ {
+ SCOPED_TRACE("After reparenting grandchild");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 111, 111, 111);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) {
+ sp<SurfaceControl> mGrandChild =
+ createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+ // draw grand child behind the foreground surface
+ asTransaction([&](Transaction& t) {
+ t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
+ });
+
+ {
+ SCOPED_TRACE("Child visible");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 200, 200, 200);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparent(mChild, nullptr);
+ t.reparentChildren(mChild, mFGSurfaceControl->getHandle());
+ });
+
+ {
+ SCOPED_TRACE("foreground visible reparenting grandchild");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 195, 63, 63);
+ }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
+
+ asTransaction([&](Transaction& t) { t.hide(mChild); });
+
+ // Since the child has the same client as the parent, it will not get
+ // detached and will be hidden.
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectFGColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+ sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> mChildNewClient =
+ createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(mChildNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
+
+ asTransaction([&](Transaction& t) {
+ t.hide(mChild);
+ t.show(mChildNewClient);
+ t.setPosition(mChildNewClient, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
+
+ asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
+
+ // Nothing should have changed.
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+ Transaction()
+ .hide(mChild)
+ .show(childNewClient)
+ .setPosition(childNewClient, 10, 10)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ Transaction().detachChildren(mFGSurfaceControl).apply();
+ Transaction().hide(childNewClient).apply();
+
+ // Nothing should have changed.
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+
+ sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
+ fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
+ 32);
+ Transaction()
+ .setLayer(newParentSurface, INT32_MAX - 1)
+ .show(newParentSurface)
+ .setPosition(newParentSurface, 20, 20)
+ .reparent(childNewClient, newParentSurface->getHandle())
+ .apply();
+ {
+ mCapture = screenshot();
+ // Child is now hidden.
+ mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
+ }
+}
+TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+ Transaction()
+ .hide(mChild)
+ .show(childNewClient)
+ .setPosition(childNewClient, 10, 10)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ Rect rect = Rect(74, 74, 84, 84);
+ mCapture->expectBorder(rect, Color{195, 63, 63, 255});
+ mCapture->expectColor(rect, Color{200, 200, 200, 255});
+ }
+
+ Transaction()
+ .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber())
+ .apply();
+ Transaction().detachChildren(mFGSurfaceControl).apply();
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
+
+ // BufferLayer can still dequeue buffers even though there's a detached layer with a
+ // deferred transaction.
+ {
+ SCOPED_TRACE("new buffer");
+ mCapture = screenshot();
+ Rect rect = Rect(74, 74, 84, 84);
+ mCapture->expectBorder(rect, Color::RED);
+ mCapture->expectColor(rect, Color{200, 200, 200, 255});
+ }
+}
+
+TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ // We've positioned the child in the top left.
+ mCapture->expectChildColor(0, 0);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // We cause scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
+
+ {
+ mCapture = screenshot();
+ // We've positioned the child in the top left.
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(10, 10);
+ mCapture->expectChildColor(19, 29);
+ // And now it should be scaled all the way to 20x30
+ mCapture->expectFGColor(20, 30);
+ }
+}
+
+// Regression test for b/37673612
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ // We've positioned the child in the top left.
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 14);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
+ }
+ // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+ // the WM specified state size.
+ asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ {
+ // The child should still be in the same place and not have any strange scaling as in
+ // b/37673612.
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectFGColor(10, 10);
+ }
+}
+
+// A child with a buffer transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 100, 100);
+ });
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should be cropped by the new parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(99, 63);
+ mCapture->expectFGColor(100, 63);
+ mCapture->expectBGColor(128, 64);
+ }
+}
+
+// A child with a scale transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 200, 200);
+ });
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Set a scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
+
+ // Child should inherit its parents scale but should be cropped by its parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(127, 127);
+ mCapture->expectBGColor(128, 128);
+ }
+}
+
+// Regression test for b/127368943
+// Child should ignore the buffer transform but apply parent scale transform.
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 14);
+ mCapture->expectFGColor(10, 15);
+ }
+
+ // Change the size of the foreground to 128 * 64 so we can test rotation as well.
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ t.setSize(mFGSurfaceControl, 128, 64);
+ });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
+ // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 32, 64);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should ignore the buffer transform but apply the 2.0 scale from parent.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(19, 29);
+ mCapture->expectFGColor(20, 30);
+ }
+}
+
+TEST_F(ChildLayerTest, Bug36858924) {
+ // Destroy the child layer
+ mChild.clear();
+
+ // Now recreate it as hidden
+ mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
+
+ // Show the child layer in a deferred transaction
+ asTransaction([&](Transaction& t) {
+ t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber());
+ t.show(mChild);
+ });
+
+ // Render the foreground surface a few times
+ //
+ // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
+ // frame because SurfaceFlinger would never process the deferred transaction and would therefore
+ // never acquire/release the first buffer
+ ALOGI("Filling 1");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
+ ALOGI("Filling 2");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255);
+ ALOGI("Filling 3");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0);
+ ALOGI("Filling 4");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
+}
+
+TEST_F(ChildLayerTest, Reparent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ // In reparenting we should have exposed the entire foreground surface.
+ mCapture->expectFGColor(74, 74);
+ // And the child layer should now begin at 10, 10 (since the BG
+ // layer is at (0, 0)).
+ mCapture->expectBGColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentToNoParent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+ asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
+ {
+ mCapture = screenshot();
+ // The surface should now be offscreen.
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectFGColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentFromNoParent) {
+ sp<SurfaceControl> newSurface = createLayer(String8("New Surface"), 10, 10, 0);
+ ASSERT_TRUE(newSurface != nullptr);
+ ASSERT_TRUE(newSurface->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(newSurface, 63, 195, 63);
+ asTransaction([&](Transaction& t) {
+ t.hide(mChild);
+ t.show(newSurface);
+ t.setPosition(newSurface, 10, 10);
+ t.setLayer(newSurface, INT32_MAX - 2);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // At 10, 10 we should see the new surface
+ mCapture->checkPixel(10, 10, 63, 195, 63);
+ }
+
+ asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
+
+ {
+ mCapture = screenshot();
+ // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
+ // mFGSurface, putting it at 74, 74.
+ mCapture->expectFGColor(64, 64);
+ mCapture->checkPixel(74, 74, 63, 195, 63);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, NestedChildren) {
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+ {
+ mCapture = screenshot();
+ // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
+ // which begins at 64, 64
+ mCapture->checkPixel(64, 64, 50, 50, 50);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
+ sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 128, 128, 0);
+ TransactionUtils::fillSurfaceRGBA8(relative, 255, 255, 255);
+
+ Transaction t;
+ t.setLayer(relative, INT32_MAX)
+ .setRelativeLayer(mChild, relative->getHandle(), 1)
+ .setPosition(mFGSurfaceControl, 0, 0)
+ .apply(true);
+
+ // We expect that the child should have been elevated above our
+ // INT_MAX layer even though it's not a child of it.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+ mCapture->checkPixel(10, 10, 255, 255, 255);
+ }
+}
+
+class BoundlessLayerTest : public LayerUpdateTest {
+protected:
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+// Verify setting a size on a buffer layer has no effect.
+TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
+ sp<SurfaceControl> bufferLayer =
+ createSurface(mClient, "BufferLayer", 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(bufferLayer->isValid());
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
+ asTransaction([&](Transaction& t) { t.show(bufferLayer); });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
+ // Buffer layer should not extend past buffer bounds
+ mCapture->expectFGColor(95, 95);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
+// which will crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
+// a crop which will be used to crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
+ sp<SurfaceControl> cropLayer = createSurface(mClient, "CropLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(cropLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(cropLayer);
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // 5 pixels from the foreground we should see the child surface
+ mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
+ // 10 pixels from the foreground we should be back to the foreground surface
+ mCapture->expectFGColor(74, 74);
+ }
+}
+
+// Verify for boundless layer with no children, their transforms have no effect.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(colorLayer, 320, 320);
+ t.setMatrix(colorLayer, 2, 0, 0, 2);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless layer with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> boundlessLayerRightShift =
+ createSurface(mClient, "BoundlessLayerRightShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayerRightShift->isValid());
+ sp<SurfaceControl> boundlessLayerDownShift =
+ createSurface(mClient, "BoundlessLayerLeftShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, boundlessLayerRightShift.get());
+ ASSERT_TRUE(boundlessLayerDownShift->isValid());
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(boundlessLayerRightShift, 32, 0);
+ t.show(boundlessLayerRightShift);
+ t.setPosition(boundlessLayerDownShift, 0, 32);
+ t.show(boundlessLayerDownShift);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify child layers do not get clipped if they temporarily move into the negative
+// coordinate space as the result of an intermediate transformation.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
+ sp<SurfaceControl> boundlessLayer =
+ mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayer != nullptr);
+ ASSERT_TRUE(boundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ // shift child layer off bounds. If this layer was not boundless, we will
+ // expect the child layer to be cropped.
+ t.setPosition(boundlessLayer, 32, 32);
+ t.show(boundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ // undo shift by parent
+ t.setPosition(colorLayer, -32, -32);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless root layers with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> rootBoundlessLayer = createSurface(mClient, "RootBoundlessLayer", 0, 0,
+ PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+ ASSERT_TRUE(rootBoundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get());
+
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
+ t.setPosition(rootBoundlessLayer, 32, 32);
+ t.show(rootBoundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ t.hide(mFGSurfaceControl);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectBGColor(31, 31);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(97, 97);
+ }
+}
+
+class ScreenCaptureTest : public LayerUpdateTest {
+protected:
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
+ auto bgHandle = mBGSurfaceControl->getHandle();
+ ScreenCapture::captureLayers(&mCapture, bgHandle);
+ mCapture->expectBGColor(0, 0);
+ // Doesn't capture FG layer which is at 64, 64
+ mCapture->expectBGColor(64, 64);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ // Captures mFGSurfaceControl layer and its child.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ // Captures mFGSurfaceControl's child
+ ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerExclude) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .show(child2)
+ .setLayer(child, 1)
+ .setLayer(child2, 2)
+ .apply(true);
+
+ // Child2 would be visible but its excluded, so we should see child1 color instead.
+ ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
+// Like the last test but verifies that children are also exclude.
+TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+ sp<SurfaceControl> child3 = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, child2.get());
+ TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .show(child2)
+ .show(child3)
+ .setLayer(child, 1)
+ .setLayer(child2, 2)
+ .apply(true);
+
+ // Child2 would be visible but its excluded, so we should see child1 color instead.
+ ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
+TEST_F(ScreenCaptureTest, CaptureTransparent) {
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ auto childHandle = child->getHandle();
+
+ // Captures child
+ ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
+ mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
+ // Area outside of child's bounds is transparent.
+ mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
+}
+
+TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ ASSERT_NE(nullptr, child.get()) << "failed to create surface";
+ sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 10, 10, 0);
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ // Set relative layer above fg layer so should be shown above when computing all layers.
+ .setRelativeLayer(relative, fgHandle, 1)
+ .show(relative)
+ .apply(true);
+
+ // Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ // Set relative layer below fg layer but relative to child layer so it should be shown
+ // above child layer.
+ .setLayer(relative, -1)
+ .setRelativeLayer(relative, child->getHandle(), 1)
+ .show(relative)
+ .apply(true);
+
+ // Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
+ // relative value should be taken into account, placing it above child layer.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ // Relative layer is showing on top of child layer
+ mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
+}
+
+TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithSourceCrop) {
+ sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<GraphicBuffer> outBuffer;
+ Rect sourceCrop(0, 0, 10, 10);
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+ ScreenCapture sc(outBuffer);
+
+ sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
+}
+
+TEST_F(ScreenCaptureTest, CaptureBoundedLayerWithoutSourceCrop) {
+ sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
+ Rect layerCrop(0, 0, 10, 10);
+ SurfaceComposerClient::Transaction().setCrop_legacy(child, layerCrop).show(child).apply(true);
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<GraphicBuffer> outBuffer;
+ Rect sourceCrop = Rect();
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+ ScreenCapture sc(outBuffer);
+
+ sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
+}
+
+TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithoutSourceCropFails) {
+ sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<GraphicBuffer> outBuffer;
+ Rect sourceCrop = Rect();
+
+ ASSERT_EQ(BAD_VALUE, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+}
+
+TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) {
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sp<GraphicBuffer> outBuffer;
+ Rect sourceCrop = Rect();
+ ASSERT_EQ(BAD_VALUE, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+
+ TransactionUtils::fillSurfaceRGBA8(child, Color::RED);
+ SurfaceComposerClient::Transaction().apply(true);
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+ ScreenCapture sc(outBuffer);
+ sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
+}
+
+// In the following tests we verify successful skipping of a parent layer,
+// so we use the same verification logic and only change how we mutate
+// the parent layer to verify that various properties are ignored.
+class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
+public:
+ void SetUp() override {
+ LayerUpdateTest::SetUp();
+
+ mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(mChild).apply(true);
+ }
+
+ void verify(std::function<void()> verifyStartingState) {
+ // Verify starting state before a screenshot is taken.
+ verifyStartingState();
+
+ // Verify child layer does not inherit any of the properties of its
+ // parent when its screenshot is captured.
+ auto fgHandle = mFGSurfaceControl->getHandle();
+ ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->expectChildColor(0, 0);
+
+ // Verify all assumptions are still true after the screenshot is taken.
+ verifyStartingState();
+ }
+
+ std::unique_ptr<ScreenCapture> mCapture;
+ sp<SurfaceControl> mChild;
+};
+
+// Regression test b/76099859
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
+ SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+ // Even though the parent is hidden we should still capture the child.
+
+ // Before and after reparenting, verify child is properly hidden
+ // when rendering full-screen.
+ verify([&] { screenshot()->expectBGColor(64, 64); });
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
+ SurfaceComposerClient::Transaction()
+ .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
+ .apply(true);
+
+ // Even though the parent is cropped out we should still capture the child.
+
+ // Before and after reparenting, verify child is cropped by parent.
+ verify([&] { screenshot()->expectBGColor(65, 65); });
+}
+
+// Regression test b/124372894
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
+ SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
+
+ // We should not inherit the parent scaling.
+
+ // Before and after reparenting, verify child is properly scaled.
+ verify([&] { screenshot()->expectChildColor(80, 80); });
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
+
+ TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .setPosition(grandchild, 5, 5)
+ .show(grandchild)
+ .apply(true);
+
+ // Captures mFGSurfaceControl, its child, and the grandchild.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+ mCapture->checkPixel(5, 5, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureChildOnly) {
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ auto childHandle = child->getHandle();
+
+ SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
+
+ // Captures only the child layer, and not the parent.
+ ScreenCapture::captureLayers(&mCapture, childHandle);
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+}
+
+TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ auto childHandle = child->getHandle();
+
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
+ TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .setPosition(grandchild, 5, 5)
+ .show(grandchild)
+ .apply(true);
+
+ auto grandchildHandle = grandchild->getHandle();
+
+ // Captures only the grandchild.
+ ScreenCapture::captureLayers(&mCapture, grandchildHandle);
+ mCapture->checkPixel(0, 0, 50, 50, 50);
+ mCapture->checkPixel(4, 4, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureCrop) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+ PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ 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)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+ mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+ // red area below the blue area
+ mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+ // red area to the right of the blue area
+ mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+ const Rect crop = Rect(0, 0, 30, 30);
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
+ // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
+ // area visible.
+ mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureSize) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+ PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ 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)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+ mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+ // red area below the blue area
+ mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+ // red area to the right of the blue area
+ mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+ // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
+ mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
+ // red area below the blue area
+ mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED);
+ // red area to the right of the blue area
+ mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+
+ auto redLayerHandle = redLayer->getHandle();
+ Transaction().reparent(redLayer, nullptr).apply();
+ redLayer.clear();
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+
+ // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
new file mode 100644
index 0000000..b49bd54
--- /dev/null
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class MirrorLayerTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ mParentLayer = createColorLayer("Parent layer", Color::RED);
+ mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get());
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+ t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+ t.setCrop_legacy(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
+ t.setPosition(mChildLayer, 50, 50);
+ t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ t.setFlags(mChildLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mParentLayer = 0;
+ mChildLayer = 0;
+ }
+
+ sp<SurfaceControl> mParentLayer;
+ sp<SurfaceControl> mChildLayer;
+};
+
+TEST_F(MirrorLayerTest, MirrorColorLayer) {
+ sp<SurfaceControl> grandchild =
+ createColorLayer("Grandchild layer", Color::BLUE, mChildLayer.get());
+ Transaction()
+ .setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+ .setCrop_legacy(grandchild, Rect(0, 0, 200, 200))
+ .show(grandchild)
+ .apply();
+
+ // Mirror mChildLayer
+ sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ ASSERT_NE(mirrorLayer, nullptr);
+
+ // Add mirrorLayer as child of mParentLayer so it's shown on the display
+ Transaction()
+ .reparent(mirrorLayer, mParentLayer->getHandle())
+ .setPosition(mirrorLayer, 500, 500)
+ .show(mirrorLayer)
+ .apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ // Set color to white on grandchild layer.
+ Transaction().setColor(grandchild, half3{1, 1, 1}).apply();
+ {
+ SCOPED_TRACE("Updated Grandchild Layer Color");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ // Set color to black on child layer.
+ Transaction().setColor(mChildLayer, half3{0, 0, 0}).apply();
+ {
+ SCOPED_TRACE("Updated Child Layer Color");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+
+ // Remove grandchild layer
+ Transaction().reparent(grandchild, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed Grandchild Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLACK);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+
+ // Remove child layer
+ Transaction().reparent(mChildLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed Child Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+ }
+
+ // Add grandchild layer to offscreen layer
+ Transaction().reparent(grandchild, mChildLayer->getHandle()).apply();
+ {
+ SCOPED_TRACE("Added Grandchild Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+ }
+
+ // Add child layer
+ Transaction().reparent(mChildLayer, mParentLayer->getHandle()).apply();
+ {
+ SCOPED_TRACE("Added Child Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+}
+
+TEST_F(MirrorLayerTest, MirrorBufferLayer) {
+ sp<SurfaceControl> bufferQueueLayer =
+ createLayer("BufferQueueLayer", 200, 200, 0, mChildLayer.get());
+ fillBufferQueueLayerColor(bufferQueueLayer, Color::BLUE, 200, 200);
+ Transaction().show(bufferQueueLayer).apply();
+
+ sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ Transaction()
+ .reparent(mirrorLayer, mParentLayer->getHandle())
+ .setPosition(mirrorLayer, 500, 500)
+ .show(mirrorLayer)
+ .apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ fillBufferQueueLayerColor(bufferQueueLayer, Color::WHITE, 200, 200);
+ {
+ SCOPED_TRACE("Update BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ Transaction().reparent(bufferQueueLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ sp<SurfaceControl> bufferStateLayer =
+ createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState,
+ mChildLayer.get());
+ fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200);
+ Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ fillBufferStateLayerColor(bufferStateLayer, Color::WHITE, 200, 200);
+ {
+ SCOPED_TRACE("Update BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ Transaction().reparent(bufferStateLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
new file mode 100644
index 0000000..06e8761
--- /dev/null
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <ui/DisplayState.h>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState);
+ SurfaceComposerClient::getActiveDisplayConfig(mMainDisplay, &mMainDisplayConfig);
+
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&mProducer, &consumer);
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(mMainDisplayConfig.resolution.getWidth(),
+ mMainDisplayConfig.resolution.getHeight());
+ }
+
+ virtual void TearDown() {
+ SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ LayerTransactionTest::TearDown();
+ mColorLayer = 0;
+ }
+
+ void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) {
+ mVirtualDisplay =
+ SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
+ asTransaction([&](Transaction& t) {
+ t.setDisplaySurface(mVirtualDisplay, mProducer);
+ t.setDisplayLayerStack(mVirtualDisplay, layerStack);
+ t.setDisplayProjection(mVirtualDisplay, mMainDisplayState.orientation,
+ Rect(layerStackSize), Rect(mMainDisplayConfig.resolution));
+ });
+ }
+
+ void createColorLayer(uint32_t layerStack) {
+ mColorLayer =
+ createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
+ ASSERT_TRUE(mColorLayer != nullptr);
+ ASSERT_TRUE(mColorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayerStack(mColorLayer, layerStack);
+ t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
+ t.setLayer(mColorLayer, INT32_MAX - 2);
+ t.setColor(mColorLayer,
+ half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
+ mExpectedColor.b / 255.0f});
+ t.show(mColorLayer);
+ });
+ }
+
+ ui::DisplayState mMainDisplayState;
+ DisplayConfig mMainDisplayConfig;
+ sp<IBinder> mMainDisplay;
+ sp<IBinder> mVirtualDisplay;
+ sp<IGraphicBufferProducer> mProducer;
+ sp<SurfaceControl> mColorLayer;
+ Color mExpectedColor = {63, 63, 195, 255};
+};
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
+ createDisplay(mMainDisplayState.viewport, 1 /* layerStack */);
+ createColorLayer(1 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer does not render on main display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ // Verify color layer renders correctly on virtual display.
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 255});
+}
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
+ // Create a display and set its layer stack to the main display's layer stack so
+ // the contents of the main display are mirrored on to the virtual display.
+
+ // Assumption here is that the new mirrored display has the same viewport as the
+ // primary display that it is mirroring.
+ createDisplay(mMainDisplayState.viewport, 0 /* layerStack */);
+ createColorLayer(0 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer renders correctly on main display and it is mirrored on the
+ // virtual display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
new file mode 100644
index 0000000..3e0b3c6
--- /dev/null
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class RelativeZTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ // Back layer
+ mBackgroundLayer = createColorLayer("Background layer", Color::RED);
+
+ // Front layer
+ mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
+
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+ t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
+ t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mBackgroundLayer = 0;
+ mForegroundLayer = 0;
+ }
+
+ sp<SurfaceControl> mBackgroundLayer;
+ sp<SurfaceControl> mForegroundLayer;
+};
+
+// When a layer is reparented offscreen, remove relative z order if the relative parent
+// is still onscreen so that the layer is not drawn.
+TEST_F(RelativeZTest, LayerRemoved) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ // Background layer (RED)
+ // Child layer (WHITE) (relative to foregroud layer)
+ // Foregroud layer (GREEN)
+ sp<SurfaceControl> childLayer =
+ createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
+
+ Transaction{}
+ .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
+ .show(childLayer)
+ .apply();
+
+ {
+ // The childLayer should be in front of the FG control.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLayer, nullptr).apply();
+
+ // Background layer (RED)
+ // Child layer (WHITE)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
+
+ {
+ // The relative z info for child layer should be reset, leaving FG control on top.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+}
+
+// When a layer is reparented offscreen, preseve relative z order if the relative parent
+// is also offscreen. Regression test b/132613412
+TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1 (WHITE)
+ // child level 2a (BLUE)
+ // child level 3 (GREEN) (relative to child level 2b)
+ // child level 2b (BLACK)
+ sp<SurfaceControl> childLevel1 =
+ createColorLayer("child level 1", Color::WHITE, mForegroundLayer.get());
+ sp<SurfaceControl> childLevel2a =
+ createColorLayer("child level 2a", Color::BLUE, childLevel1.get());
+ sp<SurfaceControl> childLevel2b =
+ createColorLayer("child level 2b", Color::BLACK, childLevel1.get());
+ sp<SurfaceControl> childLevel3 =
+ createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
+
+ Transaction{}
+ .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
+ .show(childLevel2a)
+ .show(childLevel2b)
+ .show(childLevel3)
+ .apply();
+
+ {
+ // The childLevel3 should be in front of childLevel2b.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLevel1, nullptr).apply();
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1 (WHITE)
+ // child level 2 back (BLUE)
+ // child level 3 (GREEN) (relative to child level 2b)
+ // child level 2 front (BLACK)
+ Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
+
+ {
+ // Nothing should change at this point since relative z info was preserved.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+}
+
+TEST_F(RelativeZTest, LayerAndRelativeRemoved) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // Child layer (BLUE) (relative to relativeToLayer layer)
+ // Relative layer (WHITE)
+ sp<SurfaceControl> childLayer =
+ createColorLayer("Child layer", Color::BLUE, mForegroundLayer.get());
+ sp<SurfaceControl> relativeToLayer =
+ createColorLayer("Relative layer", Color::WHITE, mForegroundLayer.get());
+
+ Transaction{}
+ .setRelativeLayer(childLayer, relativeToLayer->getHandle(), 1)
+ .show(childLayer)
+ .show(relativeToLayer)
+ .apply();
+
+ {
+ // The childLayer should be in front of relativeToLayer.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+ }
+
+ // Remove layer that childLayer is relative to
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // Child layer (BLUE) (relative to relativeToLayer layer)
+ Transaction{}.reparent(relativeToLayer, nullptr).apply();
+ relativeToLayer = 0;
+
+ {
+ // The child layer is relative to an deleted layer so it won't be drawn.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLayer, nullptr).apply();
+
+ {
+ // The child layer is offscreen, so it won't be drawn.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // Child layer (BLUE)
+ Transaction{}.reparent(childLayer, mForegroundLayer->getHandle()).apply();
+
+ {
+ // The relative z info for child layer should be reset, leaving the child layer on top.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+ }
+}
+
+// Preserve the relative z order when a layer is reparented to a layer that's already offscreen
+TEST_F(RelativeZTest, LayerWithRelativeReparentedToOffscreen) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ Color testLayerColor = {255, 100, 0, 255};
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1a (testLayerColor) (relative to child level 2b)
+ // child level 1b (WHITE)
+ // child level 2a (BLUE)
+ // child level 2b (BLACK)
+ sp<SurfaceControl> childLevel1a =
+ createColorLayer("child level 1a", testLayerColor, mForegroundLayer.get());
+ sp<SurfaceControl> childLevel1b =
+ createColorLayer("child level 1b", Color::WHITE, mForegroundLayer.get());
+ sp<SurfaceControl> childLevel2a =
+ createColorLayer("child level 2a", Color::BLUE, childLevel1b.get());
+ sp<SurfaceControl> childLevel2b =
+ createColorLayer("child level 2b", Color::BLACK, childLevel1b.get());
+
+ Transaction{}
+ .setRelativeLayer(childLevel1a, childLevel2b->getHandle(), 1)
+ .show(childLevel1a)
+ .show(childLevel1b)
+ .show(childLevel2a)
+ .show(childLevel2b)
+ .apply();
+
+ {
+ // The childLevel1a should be in front of childLevel2b.
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), testLayerColor);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1a (testLayerColor) (relative to child level 2b)
+ Transaction{}.reparent(childLevel1b, nullptr).apply();
+
+ // // Background layer (RED)
+ // // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLevel1a, childLevel2a->getHandle()).apply();
+
+ {
+ // The childLevel1a and childLevel1b are no longer on screen
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::GREEN);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1b (WHITE)
+ // child level 2a (BLUE)
+ // child level 1a (testLayerColor) (relative to child level 2b)
+ // child level 2b (BLACK)
+ Transaction{}.reparent(childLevel1b, mForegroundLayer->getHandle()).apply();
+
+ {
+ // Nothing should change at this point since relative z info was preserved.
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), testLayerColor);
+ }
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp
new file mode 100644
index 0000000..02ba9e2
--- /dev/null
+++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <system/window.h>
+
+#include <thread>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetFrameRateTest : public LayerTransactionTest {
+protected:
+ void TearDown() {
+ mLayer = nullptr;
+ LayerTransactionTest::TearDown();
+ }
+
+ void CreateLayer(uint32_t layerType) {
+ ASSERT_EQ(nullptr, mLayer.get());
+ mLayerType = layerType;
+ ASSERT_NO_FATAL_FAILURE(mLayer = createLayer("TestLayer", mLayerWidth, mLayerHeight,
+ /*flags=*/mLayerType));
+ ASSERT_NE(nullptr, mLayer.get());
+ }
+
+ void PostBuffers(const Color& color) {
+ auto startTime = systemTime();
+ while (systemTime() - startTime < s2ns(1)) {
+ ASSERT_NO_FATAL_FAILURE(
+ fillLayerColor(mLayerType, mLayer, color, mLayerWidth, mLayerHeight));
+ std::this_thread::sleep_for(100ms);
+ }
+ }
+
+ const int mLayerWidth = 32;
+ const int mLayerHeight = 32;
+ sp<SurfaceControl> mLayer;
+ uint32_t mLayerType;
+};
+
+TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) {
+ CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue);
+ native_window_set_frame_rate(mLayer->getSurface().get(), 100.f,
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+ Transaction()
+ .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .apply();
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+ native_window_set_frame_rate(mLayer->getSurface().get(), 300.f,
+ ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+}
+
+TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) {
+ CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState);
+ Transaction()
+ .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+ .apply();
+ ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN));
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SetGeometry_test.cpp b/services/surfaceflinger/tests/SetGeometry_test.cpp
new file mode 100644
index 0000000..5fe2513
--- /dev/null
+++ b/services/surfaceflinger/tests/SetGeometry_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetGeometryTest : public LayerTransactionTest {
+protected:
+ void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mLayer = createLayer("Layer", mLayerWidth, mLayerHeight);
+ fillBufferQueueLayerColor(mLayer, Color::RED, mLayerWidth, mLayerHeight);
+ asTransaction([&](Transaction& t) { t.setLayer(mLayer, INT32_MAX - 1).show(mLayer); });
+
+ {
+ SCOPED_TRACE("init");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(Rect(0, 0, mLayerWidth, mLayerHeight), Color::RED);
+ sc->expectBorder(Rect(0, 0, mLayerWidth, mLayerHeight), Color::BLACK);
+ }
+ }
+
+ void TearDown() {
+ LayerTransactionTest::TearDown();
+ sc = 0;
+ mLayer = 0;
+ }
+
+ std::unique_ptr<ScreenCapture> sc;
+ sp<SurfaceControl> mLayer;
+ const int mLayerWidth = 100;
+ const int mLayerHeight = 200;
+};
+
+TEST_F(SetGeometryTest, SourceAtZeroNoScale) {
+ Rect source = Rect(0, 0, 30, 30);
+ Rect dest = Rect(60, 60, 90, 90);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("geometry applied");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+TEST_F(SetGeometryTest, SourceNotAtZero) {
+ Rect source = Rect(40, 40, 70, 70);
+ Rect dest = Rect(60, 60, 90, 90);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("geometry applied");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+TEST_F(SetGeometryTest, Scale) {
+ Rect source = Rect(0, 0, 100, 200);
+ Rect dest = Rect(0, 0, 200, 400);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("Scaled by 2");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+
+ dest = Rect(0, 0, 50, 100);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+ {
+ SCOPED_TRACE("Scaled by .5");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index ee857b0..e9b6ba0 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <gtest/gtest.h>
#include <gui/SurfaceComposerClient.h>
@@ -107,3 +111,6 @@
}
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6b4634a..cf7d570 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*"
+ "filter": ""
}
}
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 5cc946a..8d97f27 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -14,20 +14,19 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-
#include <gtest/gtest.h>
-
-#include <android/native_window.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <fstream>
#include <random>
@@ -36,6 +35,9 @@
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Trace = surfaceflinger::Trace;
+using Increment = surfaceflinger::Increment;
constexpr int32_t SCALING_UPDATE = 1;
constexpr uint32_t BUFFER_UPDATES = 18;
@@ -43,18 +45,23 @@
constexpr uint32_t SIZE_UPDATE = 134;
constexpr uint32_t STACK_UPDATE = 1;
constexpr uint64_t DEFERRED_UPDATE = 0;
+constexpr int32_t RELATIVE_Z = 42;
constexpr float ALPHA_UPDATE = 0.29f;
constexpr float CORNER_RADIUS_UPDATE = 0.2f;
+constexpr int BACKGROUND_BLUR_RADIUS_UPDATE = 24;
constexpr float POSITION_UPDATE = 121;
const Rect CROP_UPDATE(16, 16, 32, 32);
+const float SHADOW_RADIUS_UPDATE = 35.0f;
const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
-constexpr auto TEST_SURFACE_NAME = "BG Interceptor Test Surface";
-constexpr auto UNIQUE_TEST_SURFACE_NAME = "BG Interceptor Test Surface#0";
+constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface";
+constexpr auto TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface";
+constexpr auto UNIQUE_TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface#0";
+constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0";
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
@@ -136,12 +143,16 @@
void TearDown() override {
mComposerClient->dispose();
mBGSurfaceControl.clear();
+ mFGSurfaceControl.clear();
mComposerClient.clear();
+ system("setenforce 1");
}
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mFGSurfaceControl;
int32_t mBGLayerId;
+ int32_t mFGLayerId;
public:
using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&);
@@ -169,6 +180,8 @@
bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
+ bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+ bool foundBackgroundBlurRadius);
bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -177,6 +190,11 @@
bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
+ bool reparentUpdateFound(const SurfaceChange& change, bool found);
+ bool relativeParentUpdateFound(const SurfaceChange& change, bool found);
+ bool detachChildrenUpdateFound(const SurfaceChange& change, bool found);
+ bool reparentChildrenUpdateFound(const SurfaceChange& change, bool found);
+ bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found);
bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
// Find all of the updates in the single trace
@@ -201,6 +219,7 @@
void layerUpdate(Transaction&);
void cropUpdate(Transaction&);
void cornerRadiusUpdate(Transaction&);
+ void backgroundBlurRadiusUpdate(Transaction&);
void matrixUpdate(Transaction&);
void overrideScalingModeUpdate(Transaction&);
void transparentRegionHintUpdate(Transaction&);
@@ -209,6 +228,11 @@
void opaqueFlagUpdate(Transaction&);
void secureFlagUpdate(Transaction&);
void deferredTransactionUpdate(Transaction&);
+ void reparentUpdate(Transaction&);
+ void relativeParentUpdate(Transaction&);
+ void detachChildrenUpdate(Transaction&);
+ void reparentChildrenUpdate(Transaction&);
+ void shadowRadiusUpdate(Transaction&);
void surfaceCreation(Transaction&);
void displayCreation(Transaction&);
void displayDeletion(Transaction&);
@@ -243,28 +267,37 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
// Background surface
- mBGSurfaceControl = mComposerClient->createSurface(
- String8(TEST_SURFACE_NAME), displayWidth, displayHeight,
- PIXEL_FORMAT_RGBA_8888, 0);
+ mBGSurfaceControl =
+ mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), resolution.getWidth(),
+ resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
+ // Foreground surface
+ mFGSurfaceControl =
+ mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), resolution.getWidth(),
+ resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mFGSurfaceControl != nullptr);
+ ASSERT_TRUE(mFGSurfaceControl->isValid());
+
Transaction t;
t.setDisplayLayerStack(display, 0);
- ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
- .show(mBGSurfaceControl)
- .apply());
+ ASSERT_EQ(NO_ERROR,
+ t.setLayer(mBGSurfaceControl, INT_MAX - 3)
+ .show(mBGSurfaceControl)
+ .setLayer(mFGSurfaceControl, INT_MAX - 3)
+ .show(mFGSurfaceControl)
+ .apply());
}
void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
- mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_SURFACE_NAME);
+ mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_BG_SURFACE_NAME);
+ mFGLayerId = getSurfaceId(trace, UNIQUE_TEST_FG_SURFACE_NAME);
}
void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
@@ -322,6 +355,10 @@
t.setCornerRadius(mBGSurfaceControl, CORNER_RADIUS_UPDATE);
}
+void SurfaceInterceptorTest::backgroundBlurRadiusUpdate(Transaction& t) {
+ t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
+}
+
void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
}
@@ -364,6 +401,26 @@
DEFERRED_UPDATE);
}
+void SurfaceInterceptorTest::reparentUpdate(Transaction& t) {
+ t.reparent(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+}
+
+void SurfaceInterceptorTest::relativeParentUpdate(Transaction& t) {
+ t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl->getHandle(), RELATIVE_Z);
+}
+
+void SurfaceInterceptorTest::detachChildrenUpdate(Transaction& t) {
+ t.detachChildren(mBGSurfaceControl);
+}
+
+void SurfaceInterceptorTest::reparentChildrenUpdate(Transaction& t) {
+ t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+}
+
+void SurfaceInterceptorTest::shadowRadiusUpdate(Transaction& t) {
+ t.setShadowRadius(mBGSurfaceControl, SHADOW_RADIUS_UPDATE);
+}
+
void SurfaceInterceptorTest::displayCreation(Transaction&) {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
SurfaceComposerClient::destroyDisplay(testDisplay);
@@ -379,6 +436,7 @@
runInTransaction(&SurfaceInterceptorTest::sizeUpdate);
runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
+ runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
runInTransaction(&SurfaceInterceptorTest::layerUpdate);
runInTransaction(&SurfaceInterceptorTest::cropUpdate);
runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
@@ -389,6 +447,11 @@
runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate);
runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate);
runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
+ runInTransaction(&SurfaceInterceptorTest::reparentUpdate);
+ runInTransaction(&SurfaceInterceptorTest::reparentChildrenUpdate);
+ runInTransaction(&SurfaceInterceptorTest::detachChildrenUpdate);
+ runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate);
+ runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate);
}
void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
@@ -451,6 +514,18 @@
return foundCornerRadius;
}
+bool SurfaceInterceptorTest::backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+ bool foundBackgroundBlur) {
+ bool hasBackgroundBlur(change.background_blur_radius().background_blur_radius() ==
+ BACKGROUND_BLUR_RADIUS_UPDATE);
+ if (hasBackgroundBlur && !foundBackgroundBlur) {
+ foundBackgroundBlur = true;
+ } else if (hasBackgroundBlur && foundBackgroundBlur) {
+ []() { FAIL(); }();
+ }
+ return foundBackgroundBlur;
+}
+
bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
bool hasLayer(change.layer().layer() == LAYER_UPDATE);
if (hasLayer && !foundLayer) {
@@ -569,6 +644,57 @@
return foundDeferred;
}
+bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) {
+ bool hasId(change.reparent().parent_id() == mFGLayerId);
+ if (hasId && !found) {
+ found = true;
+ } else if (hasId && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
+bool SurfaceInterceptorTest::relativeParentUpdateFound(const SurfaceChange& change, bool found) {
+ bool hasId(change.relative_parent().relative_parent_id() == mFGLayerId);
+ if (hasId && !found) {
+ found = true;
+ } else if (hasId && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
+bool SurfaceInterceptorTest::detachChildrenUpdateFound(const SurfaceChange& change, bool found) {
+ bool detachChildren(change.detach_children().detach_children());
+ if (detachChildren && !found) {
+ found = true;
+ } else if (detachChildren && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
+bool SurfaceInterceptorTest::reparentChildrenUpdateFound(const SurfaceChange& change, bool found) {
+ bool hasId(change.reparent_children().parent_id() == mFGLayerId);
+ if (hasId && !found) {
+ found = true;
+ } else if (hasId && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
+bool SurfaceInterceptorTest::shadowRadiusUpdateFound(const SurfaceChange& change,
+ bool foundShadowRadius) {
+ bool hasShadowRadius(change.shadow_radius().radius() == SHADOW_RADIUS_UPDATE);
+ if (hasShadowRadius && !foundShadowRadius) {
+ foundShadowRadius = true;
+ } else if (hasShadowRadius && foundShadowRadius) {
+ []() { FAIL(); }();
+ }
+ return foundShadowRadius;
+}
+
bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
SurfaceChange::SurfaceChangeCase changeCase) {
bool foundUpdate = false;
@@ -596,6 +722,9 @@
case SurfaceChange::SurfaceChangeCase::kCornerRadius:
foundUpdate = cornerRadiusUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
+ foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::kMatrix:
foundUpdate = matrixUpdateFound(change, foundUpdate);
break;
@@ -620,6 +749,21 @@
case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
foundUpdate = deferredTransactionUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kReparent:
+ foundUpdate = reparentUpdateFound(change, foundUpdate);
+ break;
+ case SurfaceChange::SurfaceChangeCase::kReparentChildren:
+ foundUpdate = reparentChildrenUpdateFound(change, foundUpdate);
+ break;
+ case SurfaceChange::SurfaceChangeCase::kRelativeParent:
+ foundUpdate = relativeParentUpdateFound(change, foundUpdate);
+ break;
+ case SurfaceChange::SurfaceChangeCase::kDetachChildren:
+ foundUpdate = detachChildrenUpdateFound(change, foundUpdate);
+ break;
+ case SurfaceChange::SurfaceChangeCase::kShadowRadius:
+ foundUpdate = shadowRadiusUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::SURFACECHANGE_NOT_SET:
break;
}
@@ -644,6 +788,10 @@
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparentChildren));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDetachChildren));
}
bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
@@ -759,6 +907,11 @@
SurfaceChange::SurfaceChangeCase::kCornerRadius);
}
+TEST_F(SurfaceInterceptorTest, InterceptBackgroundBlurRadiusUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate,
+ SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
+}
+
TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
}
@@ -798,6 +951,31 @@
SurfaceChange::SurfaceChangeCase::kDeferredTransaction);
}
+TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::reparentUpdate,
+ SurfaceChange::SurfaceChangeCase::kReparent);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptReparentChildrenUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::reparentChildrenUpdate,
+ SurfaceChange::SurfaceChangeCase::kReparentChildren);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptRelativeParentUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::relativeParentUpdate,
+ SurfaceChange::SurfaceChangeCase::kRelativeParent);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptDetachChildrenUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::detachChildrenUpdate,
+ SurfaceChange::SurfaceChangeCase::kDetachChildren);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptShadowRadiusUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::shadowRadiusUpdate,
+ SurfaceChange::SurfaceChangeCase::kShadowRadius);
+}
+
TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
captureTest(&SurfaceInterceptorTest::runAllUpdates,
&SurfaceInterceptorTest::assertAllUpdatesFound);
@@ -861,5 +1039,7 @@
ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
}
-
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
new file mode 100644
index 0000000..f0af363
--- /dev/null
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#ifndef ANDROID_TRANSACTION_TEST_HARNESSES
+#define ANDROID_TRANSACTION_TEST_HARNESSES
+
+#include <ui/DisplayState.h>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerRenderPathTestHarness {
+public:
+ LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
+ : mDelegate(delegate), mRenderPath(renderPath) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ switch (mRenderPath) {
+ case RenderPath::SCREENSHOT:
+ return mDelegate->screenshot();
+ case RenderPath::VIRTUAL_DISPLAY:
+
+ const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+
+ ui::DisplayState displayState;
+ SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+
+ DisplayConfig displayConfig;
+ SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+ const ui::Size& resolution = displayConfig.resolution;
+
+ sp<IBinder> vDisplay;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ sp<BufferItemConsumer> itemConsumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
+
+ itemConsumer = new BufferItemConsumer(consumer,
+ // Sample usage bits from screenrecord
+ GRALLOC_USAGE_HW_VIDEO_ENCODER |
+ GRALLOC_USAGE_SW_READ_OFTEN);
+
+ vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
+ false /*secure*/);
+
+ SurfaceComposerClient::Transaction t;
+ t.setDisplaySurface(vDisplay, producer);
+ t.setDisplayLayerStack(vDisplay, 0);
+ t.setDisplayProjection(vDisplay, displayState.orientation,
+ Rect(displayState.viewport), Rect(resolution));
+ t.apply();
+ SurfaceComposerClient::Transaction().apply(true);
+ BufferItem item;
+ itemConsumer->acquireBuffer(&item, 0, true);
+ auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+ itemConsumer->releaseBuffer(item);
+ SurfaceComposerClient::destroyDisplay(vDisplay);
+ return sc;
+ }
+ }
+
+protected:
+ LayerTransactionTest* mDelegate;
+ RenderPath mRenderPath;
+};
+
+class LayerTypeTransactionHarness : public LayerTransactionTest {
+public:
+ LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
+
+ sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0, SurfaceControl* parent = nullptr,
+ uint32_t* outTransformHint = nullptr,
+ PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
+ // 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, parent,
+ outTransformHint, format);
+ }
+
+ 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;
+};
+} // namespace android
+#endif
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
deleted file mode 100644
index 71016db..0000000
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ /dev/null
@@ -1,6218 +0,0 @@
-/*
- * Copyright (C) 2011 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 <algorithm>
-#include <chrono>
-#include <cinttypes>
-#include <functional>
-#include <limits>
-#include <ostream>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-#include <android/native_window.h>
-
-#include <binder/ProcessState.h>
-#include <gui/BufferItemConsumer.h>
-#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/LayerState.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <hardware/hwcomposer_defs.h>
-#include <private/android_filesystem_config.h>
-#include <private/gui/ComposerService.h>
-
-#include <ui/ColorSpace.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-#include <utils/String8.h>
-
-#include <math.h>
-#include <math/vec3.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "BufferGenerator.h"
-
-namespace android {
-
-namespace {
-
-struct Color {
- uint8_t r;
- uint8_t g;
- uint8_t b;
- uint8_t a;
-
- static const Color RED;
- static const Color GREEN;
- static const Color BLUE;
- static const Color WHITE;
- static const Color BLACK;
- static const Color TRANSPARENT;
-};
-
-const Color Color::RED{255, 0, 0, 255};
-const Color Color::GREEN{0, 255, 0, 255};
-const Color Color::BLUE{0, 0, 255, 255};
-const Color Color::WHITE{255, 255, 255, 255};
-const Color Color::BLACK{0, 0, 0, 255};
-const Color Color::TRANSPARENT{0, 0, 0, 0};
-
-using android::hardware::graphics::common::V1_1::BufferUsage;
-using namespace std::chrono_literals;
-
-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 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;
- }
-
- 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;
- dst[3] = color.a;
- dst += 4;
- }
- }
-}
-
-// 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) {
- int32_t x = rect.left;
- int32_t y = rect.top;
- int32_t width = rect.right - rect.left;
- int32_t height = rect.bottom - rect.top;
-
- int32_t bufferWidth = int32_t(outBuffer->getWidth());
- int32_t bufferHeight = int32_t(outBuffer->getHeight());
- if (x + width > bufferWidth) {
- x = std::min(x, bufferWidth);
- width = bufferWidth - x;
- }
- if (y + height > bufferHeight) {
- y = std::min(y, bufferHeight);
- height = bufferHeight - y;
- }
-
- auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
- uint8_t tmp = a >= b ? a - b : b - a;
- return tmp <= tolerance;
- };
- for (int32_t j = 0; j < height; j++) {
- const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
- for (int32_t i = 0; i < width; i++) {
- const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
- EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
- << "pixel @ (" << x + i << ", " << y + j << "): "
- << "expected (" << color << "), "
- << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
- src += 4;
- }
- }
-}
-
-} // anonymous namespace
-
-using Transaction = SurfaceComposerClient::Transaction;
-
-// Fill an RGBA_8888 formatted surface with a single color.
-static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
- bool unlock = true) {
- ANativeWindow_Buffer outBuffer;
- sp<Surface> s = sc->getSurface();
- ASSERT_TRUE(s != nullptr);
- ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
- uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
- for (int y = 0; y < outBuffer.height; y++) {
- for (int x = 0; x < outBuffer.width; x++) {
- uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
- pixel[0] = r;
- pixel[1] = g;
- pixel[2] = b;
- pixel[3] = 255;
- }
- }
- if (unlock) {
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
- }
-}
-
-// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
-// individual pixel values for testing purposes.
-class ScreenCapture : public RefBase {
-public:
- static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
- captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
- }
-
- static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
- const auto sf = ComposerService::getComposerService();
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- static void captureChildLayersExcluding(
- std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR,
- sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
- ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
- 1.0f, true));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
- ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
- expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
- }
-
- void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
- ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
- const bool leftBorder = rect.left > 0;
- const bool topBorder = rect.top > 0;
- const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
- const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
-
- if (topBorder) {
- Rect top(rect.left, rect.top - 1, rect.right, rect.top);
- if (leftBorder) {
- top.left -= 1;
- }
- if (rightBorder) {
- top.right += 1;
- }
- expectColor(top, color, tolerance);
- }
- if (leftBorder) {
- Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
- expectColor(left, color, tolerance);
- }
- if (rightBorder) {
- Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
- expectColor(right, color, tolerance);
- }
- if (bottomBorder) {
- Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
- if (leftBorder) {
- bottom.left -= 1;
- }
- if (rightBorder) {
- bottom.right += 1;
- }
- expectColor(bottom, color, tolerance);
- }
- }
-
- void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
- const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
- uint8_t tolerance = 0) {
- ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
-
- const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
- const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
- // avoid checking borders due to unspecified filtering behavior
- const int32_t offsetX = filtered ? 2 : 0;
- const int32_t offsetY = filtered ? 2 : 0;
- expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
- tolerance);
- expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
- tolerance);
- expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
- tolerance);
- expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
- bottomRight, tolerance);
- }
-
- void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
- ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
- const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
- if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
- String8 err(String8::format("pixel @ (%3d, %3d): "
- "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
- x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
- EXPECT_EQ(String8(), err) << err.string();
- }
- }
-
- void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
-
- void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
-
- void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
-
- explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
- mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
- }
-
- ~ScreenCapture() { mOutBuffer->unlock(); }
-
-private:
- sp<GraphicBuffer> mOutBuffer;
- uint8_t* mPixels = nullptr;
-};
-
-class LayerTransactionTest : public ::testing::Test {
-protected:
- void SetUp() override {
- mClient = new SurfaceComposerClient;
- ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
-
- ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
-
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
- }
-
- virtual void TearDown() {
- mBlackBgSurface = 0;
- mClient->dispose();
- mClient = 0;
- }
-
- virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
- const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr,
- PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
- auto layer = createSurface(client, name, width, height, format, flags, parent);
-
- Transaction t;
- t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
-
- status_t error = t.apply();
- if (error != NO_ERROR) {
- ADD_FAILURE() << "failed to initialize SurfaceControl";
- layer.clear();
- }
-
- return layer;
- }
-
- virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
- const char* name, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t flags,
- SurfaceControl* parent = nullptr) {
- auto layer = client->createSurface(String8(name), width, height, format, flags, parent);
- EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
- return layer;
- }
-
- virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr,
- PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
- return createLayer(mClient, name, width, height, flags, parent, format);
- }
-
- sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
- SurfaceControl* parent = nullptr) {
- auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, parent);
- asTransaction([&](Transaction& t) {
- t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
- t.setAlpha(colorLayer, color.a / 255.0f);
- });
- return colorLayer;
- }
-
- ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
- // wait for previous transactions (such as setSize) to complete
- Transaction().apply(true);
-
- ANativeWindow_Buffer buffer = {};
- EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
-
- return buffer;
- }
-
- void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
- ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
-
- // wait for the newly posted buffer to be latched
- waitForLayerBuffers();
- }
-
- virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
- int32_t bufferWidth, int32_t bufferHeight) {
- ANativeWindow_Buffer buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
- fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
- postBufferQueueLayerBuffer(layer);
- }
-
- 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).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 = getBufferQueueLayerBuffer(layer));
- ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
-
- 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);
-
- 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();
- }
-
- std::unique_ptr<ScreenCapture> screenshot() {
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- return screenshot;
- }
-
- void asTransaction(const std::function<void(Transaction&)>& exec) {
- Transaction t;
- exec(t);
- t.apply(true);
- }
-
- static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
- static BufferGenerator bufferGenerator;
- return bufferGenerator.get(outBuffer, outFence);
- }
-
- sp<SurfaceComposerClient> mClient;
-
- sp<IBinder> mDisplay;
- uint32_t mDisplayWidth;
- uint32_t mDisplayHeight;
- uint32_t mDisplayLayerStack;
- Rect mDisplayRect = Rect::INVALID_RECT;
-
- // leave room for ~256 layers
- const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
-
- sp<SurfaceControl> mBlackBgSurface;
- bool mColorManagementUsed;
-
-private:
- void SetUpDisplay() {
- mDisplay = mClient->getInternalDisplayToken();
- ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
-
- // get display width/height
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
- mDisplayRect =
- Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight));
-
- // After a new buffer is queued, SurfaceFlinger is notified and will
- // latch the new buffer on next vsync. Let's heuristically wait for 3
- // vsyncs.
- mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
-
- mDisplayLayerStack = 0;
-
- mBlackBgSurface =
- createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
-
- // set layer stack (b/68888219)
- Transaction t;
- t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
- t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
- t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
- t.setColor(mBlackBgSurface, half3{0, 0, 0});
- t.setLayer(mBlackBgSurface, mLayerZBase);
- t.apply();
- }
-
- void waitForLayerBuffers() {
- // Request an empty transaction to get applied synchronously to ensure the buffer is
- // latched.
- Transaction().apply(true);
- usleep(mBufferPostDelay);
- }
-
- int32_t mBufferPostDelay;
-
- friend class LayerRenderPathTestHarness;
-};
-enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
-
-class LayerRenderPathTestHarness {
-public:
- LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
- : mDelegate(delegate), mRenderPath(renderPath) {}
-
- std::unique_ptr<ScreenCapture> getScreenCapture() {
- switch (mRenderPath) {
- case RenderPath::SCREENSHOT:
- return mDelegate->screenshot();
- case RenderPath::VIRTUAL_DISPLAY:
-
- const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- DisplayInfo mainDisplayInfo;
- SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
-
- sp<IBinder> vDisplay;
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- sp<BufferItemConsumer> itemConsumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
-
- consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
-
- itemConsumer = new BufferItemConsumer(consumer,
- // Sample usage bits from screenrecord
- GRALLOC_USAGE_HW_VIDEO_ENCODER |
- GRALLOC_USAGE_SW_READ_OFTEN);
-
- vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
- false /*secure*/);
-
- SurfaceComposerClient::Transaction t;
- t.setDisplaySurface(vDisplay, producer);
- t.setDisplayLayerStack(vDisplay, 0);
- t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
- Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
- Rect(mainDisplayInfo.w, mainDisplayInfo.h));
- t.apply();
- SurfaceComposerClient::Transaction().apply(true);
- BufferItem item;
- itemConsumer->acquireBuffer(&item, 0, true);
- auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
- itemConsumer->releaseBuffer(item);
- SurfaceComposerClient::destroyDisplay(vDisplay);
- return sc;
- }
- }
-
-protected:
- LayerTransactionTest* mDelegate;
- RenderPath mRenderPath;
-};
-
-class LayerTypeTransactionHarness : public LayerTransactionTest {
-public:
- LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
-
- sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr,
- PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
- // 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, parent,
- format);
- }
-
- 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;
-};
-
-class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
- public ::testing::WithParamInterface<uint32_t> {
-public:
- LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
-};
-
-class LayerTypeAndRenderTypeTransactionTest
- : public LayerTypeTransactionHarness,
- public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
-public:
- LayerTypeAndRenderTypeTransactionTest()
- : LayerTypeTransactionHarness(std::get<0>(GetParam())),
- mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
-
- std::unique_ptr<ScreenCapture> getScreenCapture() {
- return mRenderPathHarness.getScreenCapture();
- }
-
-protected:
- LayerRenderPathTestHarness mRenderPathHarness;
-};
-
-// Environment for starting up binder threads. This is required for testing
-// virtual displays, as BufferQueue parameters may be queried over binder.
-class BinderEnvironment : public ::testing::Environment {
-public:
- void SetUp() override { ProcessState::self()->startThreadPool(); }
-};
-
-::testing::Environment* const binderEnv =
- ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
-
-class LayerRenderTypeTransactionTest : public LayerTransactionTest,
- public ::testing::WithParamInterface<RenderPath> {
-public:
- LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
-
- std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
- void setRelativeZBasicHelper(uint32_t layerType);
- void setRelativeZGroupHelper(uint32_t layerType);
- void setAlphaBasicHelper(uint32_t layerType);
- void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
- Color finalColor);
-
-protected:
- LayerRenderPathTestHarness mHarness;
-};
-
-INSTANTIATE_TEST_CASE_P(
- LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
- ::testing::Combine(
- ::testing::Values(
- static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
- static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
- ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
-
-INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
- ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
-
-INSTANTIATE_TEST_CASE_P(
- LayerTypeTransactionTests, LayerTypeTransactionTest,
- ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
- static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("default position");
- const Rect rect(0, 0, 32, 32);
- auto shot = getScreenCapture();
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- Transaction().setPosition(layer, 5, 10).apply();
- {
- SCOPED_TRACE("new position");
- const Rect rect(5, 10, 37, 42);
- auto shot = getScreenCapture();
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(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
- // loss (b/69315223)
- const float epsilon = 1.0f / 16.0f;
- Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
- {
- SCOPED_TRACE("rounding down");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
- {
- SCOPED_TRACE("rounding up");
- getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setPosition(layer, -32, -32).apply();
- {
- SCOPED_TRACE("negative coordinates");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-
- Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
- {
- SCOPED_TRACE("positive coordinates");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // partially out of bounds
- Transaction().setPosition(layer, -30, -30).apply();
- {
- SCOPED_TRACE("negative coordinates");
- getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
- }
-
- Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
- {
- SCOPED_TRACE("positive coordinates");
- getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
- mDisplayHeight),
- Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setPosition is applied immediately by default, with or without resize
- // pending
- Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(5, 10, 37, 42);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- 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();
- {
- SCOPED_TRACE("new position pending");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setPosition(layer, 15, 20).apply();
- {
- SCOPED_TRACE("pending new position modified");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- // finally resize and latch the buffer
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("new position applied");
- getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setPosition is not immediate even with SCALE_TO_WINDOW override
- Transaction()
- .setPosition(layer, 5, 10)
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("new position pending");
- getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("new position applied");
- getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 32, 32);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 64, 64);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
- // cannot test robustness against invalid sizes (zero or really huge)
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
- Transaction()
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
- Transaction().setLayer(layerR, mLayerZBase + 1).apply();
- {
- SCOPED_TRACE("layerR");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setLayer(layerG, mLayerZBase + 2).apply();
- {
- SCOPED_TRACE("layerG");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer);
- Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- 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, 32, 32));
-
- Transaction()
- .reparent(layerR, parent->getHandle())
- .reparent(layerG, parent->getHandle())
- .apply();
- Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
- {
- SCOPED_TRACE("layerR");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setLayer(layerR, -3).apply();
- {
- SCOPED_TRACE("layerG");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
- }
-}
-
-void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
-
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setPosition(layerG, 16, 16)
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- Transaction()
- .setFrame(layerR, Rect(0, 0, 32, 32))
- .setFrame(layerG, Rect(16, 16, 48, 48))
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
- break;
- default:
- ASSERT_FALSE(true) << "Unsupported layer type";
- }
- {
- SCOPED_TRACE("layerG above");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
- }
-
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
- {
- SCOPED_TRACE("layerG below");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer);
- Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
- 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, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- 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, 32, 32));
-
- Transaction()
- .reparent(layerB, parent->getHandle())
- .apply();
-
- // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
-
- std::unique_ptr<ScreenCapture> screenshot;
- // only layerB is in this range
- sp<IBinder> parentHandle = parent->getHandle();
- ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
- screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-}
-
-TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
-
- sp<SurfaceControl> childLayer;
- ASSERT_NO_FATAL_FAILURE(
- childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
- parent.get()));
- Transaction()
- .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
- .setColor(parent, half3{0.0f, 0.0f, 0.0f})
- .show(childLayer)
- .show(parent)
- .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
- .setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
- .apply();
-
- Transaction()
- .setRelativeLayer(childLayer, parent->getHandle(), -1)
- .setLayer(childLayer, 1)
- .apply();
-
- {
- SCOPED_TRACE("setLayer above");
- // Set layer should get applied and place the child above.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
- }
-
- Transaction()
- .setLayer(childLayer, 1)
- .setRelativeLayer(childLayer, parent->getHandle(), -1)
- .apply();
-
- {
- SCOPED_TRACE("setRelative below");
- // Set relative layer should get applied and place the child below.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
- sp<SurfaceControl> relativeParent =
- LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
- 0 /* buffer height */, ISurfaceComposerClient::eFXSurfaceColor);
-
- sp<SurfaceControl> childLayer;
- ASSERT_NO_FATAL_FAILURE(
- childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
- parent.get()));
- Transaction()
- .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
- .setColor(parent, half3{0.0f, 0.0f, 0.0f})
- .setColor(relativeParent, half3{0.0f, 1.0f, 0.0f})
- .show(childLayer)
- .show(parent)
- .show(relativeParent)
- .setLayer(parent, mLayerZBase - 1)
- .setLayer(relativeParent, mLayerZBase)
- .apply();
-
- Transaction()
- .setRelativeLayer(childLayer, relativeParent->getHandle(), 1)
- .apply();
-
- {
- SCOPED_TRACE("setLayer above");
- // Set layer should get applied and place the child above.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
- }
-
- Transaction()
- .hide(relativeParent)
- .apply();
-
- {
- SCOPED_TRACE("hide relative parent");
- // The relative should no longer be visible.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
- }
-}
-
-void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- sp<SurfaceControl> layerB;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32));
-
- // layerR = 0, layerG = layerR + 3, layerB = 2
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setPosition(layerG, 8, 8)
- .setRelativeLayer(layerG, layerR->getHandle(), 3)
- .setPosition(layerB, 16, 16)
- .setLayer(layerB, mLayerZBase + 2)
- .apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- Transaction()
- .setFrame(layerR, Rect(0, 0, 32, 32))
- .setFrame(layerG, Rect(8, 8, 40, 40))
- .setRelativeLayer(layerG, layerR->getHandle(), 3)
- .setFrame(layerB, Rect(16, 16, 48, 48))
- .setLayer(layerB, mLayerZBase + 2)
- .apply();
- break;
- default:
- ASSERT_FALSE(true) << "Unsupported layer type";
- }
-
- {
- SCOPED_TRACE("(layerR < layerG) < layerB");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
- shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
- shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
- }
-
- // layerR = 4, layerG = layerR + 3, layerB = 2
- Transaction().setLayer(layerR, mLayerZBase + 4).apply();
- {
- SCOPED_TRACE("layerB < (layerR < layerG)");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
- shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
- shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
- }
-
- // layerR = 4, layerG = layerR - 3, layerB = 2
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
- {
- SCOPED_TRACE("layerB < (layerG < layerR)");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
- shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
- }
-
- // restore to absolute z
- // layerR = 4, layerG = 0, layerB = 2
- Transaction().setLayer(layerG, mLayerZBase).apply();
- {
- SCOPED_TRACE("layerG < layerB < layerR");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
- }
-
- // layerR should not affect layerG anymore
- // layerR = 1, layerG = 0, layerB = 2
- Transaction().setLayer(layerR, mLayerZBase + 1).apply();
- {
- SCOPED_TRACE("layerG < layerR < layerB");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
- Transaction()
- .setPosition(layerG, 16, 16)
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
-
- layerG.clear();
- // layerG should have been removed
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
- {
- SCOPED_TRACE("layer hidden");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-
- Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
- {
- SCOPED_TRACE("layer shown");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
- Transaction()
- .setLayer(layerR, mLayerZBase + 1)
- .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
- .apply();
- {
- SCOPED_TRACE("layerR opaque");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
- }
-
- Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
- {
- SCOPED_TRACE("layerR translucent");
- const uint8_t g = uint8_t(255 - translucentRed.a);
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
- }
-}
-
-TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- sp<GraphicBuffer> outBuffer;
- Transaction()
- .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
- .apply(true);
- ASSERT_EQ(PERMISSION_DENIED,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
- Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
- ASSERT_EQ(NO_ERROR,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-}
-
-/** RAII Wrapper around get/seteuid */
-class UIDFaker {
- uid_t oldId;
-public:
- UIDFaker(uid_t uid) {
- oldId = geteuid();
- seteuid(uid);
- }
- ~UIDFaker() {
- seteuid(oldId);
- }
-};
-
-TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- sp<GraphicBuffer> outBuffer;
- Transaction()
- .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
- .apply(true);
- ASSERT_EQ(PERMISSION_DENIED,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
- UIDFaker f(AID_SYSTEM);
-
- // By default the system can capture screenshots with secure layers but they
- // will be blacked out
- ASSERT_EQ(NO_ERROR,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
- {
- SCOPED_TRACE("as system");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
- // to receive them...we are expected to take care with the results.
- bool outCapturedSecureLayers;
- ASSERT_EQ(NO_ERROR,
- composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
- ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
- 0, false, ISurfaceComposer::eRotateNone, true));
- ASSERT_EQ(true, outCapturedSecureLayers);
- ScreenCapture sc(outBuffer);
- sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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 = 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(postBufferQueueLayerBuffer(layer));
- {
- SCOPED_TRACE("top transparent");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::BLACK);
- shot->expectColor(bottom, Color::RED);
- }
-
- Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
- {
- SCOPED_TRACE("transparent region hint pending");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::BLACK);
- shot->expectColor(bottom, Color::RED);
- }
-
- 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 = getScreenCapture();
- shot->expectColor(top, Color::RED);
- shot->expectColor(bottom, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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)
- .setFrame(layer, Rect(0, 0, 32, 32))
- .apply();
- {
- SCOPED_TRACE("top transparent");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::BLACK);
- shot->expectColor(bottom, Color::RED);
- }
-
- Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
- {
- SCOPED_TRACE("transparent region hint intermediate");
- auto shot = getScreenCapture();
- 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).apply();
- {
- SCOPED_TRACE("bottom transparent");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::RED);
- shot->expectColor(bottom, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layerTransparent;
- sp<SurfaceControl> layerR;
- ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-
- // check that transparent region hint is bound by the layer size
- Transaction()
- .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
- .setPosition(layerR, 16, 16)
- .setLayer(layerR, mLayerZBase + 1)
- .apply();
- ASSERT_NO_FATAL_FAILURE(
- fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
- getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
- sp<SurfaceControl> layerTransparent;
- sp<SurfaceControl> layerR;
- ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- // check that transparent region hint is bound by the layer size
- Transaction()
- .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
- .setFrame(layerR, Rect(16, 16, 48, 48))
- .setLayer(layerR, mLayerZBase + 1)
- .apply();
- ASSERT_NO_FATAL_FAILURE(
- fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
- getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
-}
-
-void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
- sp<SurfaceControl> layer1;
- sp<SurfaceControl> layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32));
-
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setAlpha(layer1, 0.25f)
- .setAlpha(layer2, 0.75f)
- .setPosition(layer2, 16, 0)
- .setLayer(layer2, mLayerZBase + 1)
- .apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- Transaction()
- .setAlpha(layer1, 0.25f)
- .setAlpha(layer2, 0.75f)
- .setFrame(layer1, Rect(0, 0, 32, 32))
- .setFrame(layer2, Rect(16, 0, 48, 32))
- .setLayer(layer2, mLayerZBase + 1)
- .apply();
- break;
- default:
- ASSERT_FALSE(true) << "Unsupported layer type";
- }
- {
- auto shot = getScreenCapture();
- uint8_t r = 16; // 64 * 0.25f
- uint8_t g = 48; // 64 * 0.75f
- shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
- shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255});
-
- r /= 4; // r * (1.0f - 0.75f)
- shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255});
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
- ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
- ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, 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, 32, 32));
-
- Transaction().setAlpha(layer, 2.0f).apply();
- {
- SCOPED_TRACE("clamped to 1.0f");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
- }
-
- Transaction().setAlpha(layer, -1.0f).apply();
- {
- SCOPED_TRACE("clamped to 0.0f");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
- sp<SurfaceControl> layer;
- const uint8_t size = 64;
- const uint8_t testArea = 4;
- const float cornerRadius = 20.0f;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
-
- Transaction()
- .setCornerRadius(layer, cornerRadius)
- .apply();
- {
- const uint8_t bottom = size - 1;
- const uint8_t right = size - 1;
- auto shot = getScreenCapture();
- // Transparent corners
- shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
- shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
- shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
- shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
- sp<SurfaceControl> parent;
- sp<SurfaceControl> child;
- const uint8_t size = 64;
- const uint8_t testArea = 4;
- const float cornerRadius = 20.0f;
- ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
- ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
-
- Transaction()
- .setCornerRadius(parent, cornerRadius)
- .reparent(child, parent->getHandle())
- .setPosition(child, 0, size / 2)
- .apply();
- {
- const uint8_t bottom = size - 1;
- const uint8_t right = size - 1;
- auto shot = getScreenCapture();
- // Top edge of child should not have rounded corners because it's translated in the parent
- shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
- Color::GREEN);
- // But bottom edges should have been clipped according to parent bounds
- shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
- shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
- sp<SurfaceControl> bufferLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
-
- Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(colorLayer, mLayerZBase + 1)
- .apply();
-
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
- const Color expected = {15, 51, 85, 255};
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
- Transaction().setColor(colorLayer, color).apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
- }
-}
-
-// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
-// BLUE: prior background color
-// GREEN: final background color
-// BLACK: no color or fill
-void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
- bool bufferFill, float alpha,
- Color finalColor) {
- sp<SurfaceControl> layer;
- int32_t width = 500;
- int32_t height = 500;
-
- Color fillColor = Color::RED;
- Color priorBgColor = Color::BLUE;
- Color expectedColor = Color::BLACK;
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceColor:
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
- Transaction()
- .setCrop_legacy(layer, Rect(0, 0, width, height))
- .setColor(layer, half3(1.0f, 0, 0))
- .apply();
- expectedColor = fillColor;
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
- if (bufferFill) {
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
- expectedColor = fillColor;
- }
- Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
- if (bufferFill) {
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
- expectedColor = fillColor;
- }
- Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
- break;
- default:
- GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
- return;
- }
-
- if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
- Transaction()
- .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
- .apply();
- if (!bufferFill) {
- expectedColor = priorBgColor;
- }
- }
-
- {
- SCOPED_TRACE("default before setting background color layer");
- screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
- }
- Transaction()
- .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
- .apply();
-
- {
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, width, height), finalColor);
- shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
- .apply();
-
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
- sp<SurfaceControl> bufferLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
-
- const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
- const float alpha = 0.25f;
- const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
- Transaction()
- .setColor(colorLayer, color)
- .setAlpha(colorLayer, alpha)
- .setLayer(colorLayer, mLayerZBase + 1)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
- sp<SurfaceControl> bufferLayer;
- sp<SurfaceControl> parentLayer;
- 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(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
- const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
- const float alpha = 0.25f;
- const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
- // this is handwavy, but the precision loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
- Transaction()
- .reparent(colorLayer, parentLayer->getHandle())
- .setColor(colorLayer, color)
- .setAlpha(parentLayer, alpha)
- .setLayer(parentLayer, mLayerZBase + 1)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
- sp<SurfaceControl> bufferLayer;
- ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
-
- // color is ignored
- Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
- {
- SCOPED_TRACE("non-existing layer stack");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-
- Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
- {
- SCOPED_TRACE("original layer stack");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) {
- int32_t width = 100;
- int32_t height = 100;
- Rect crop = Rect(0, 0, width, height);
-
- sp<SurfaceControl> behindLayer = createColorLayer("Behind layer", Color::RED);
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", width, height, 0, nullptr, PIXEL_FORMAT_RGBX_8888));
-
- Transaction()
- .setLayer(layer, INT32_MAX - 1)
- .show(layer)
- .setLayerStack(behindLayer, mDisplayLayerStack)
- .setCrop_legacy(behindLayer, crop)
- .setLayer(behindLayer, INT32_MAX - 2)
- .show(behindLayer)
- .apply();
-
- sp<Surface> surface = layer->getSurface();
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
-
- if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
- Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
- } else {
- Transaction().setBuffer(layer, buffer).apply();
- }
-
- {
- SCOPED_TRACE("Buffer Opaque Format");
- auto shot = screenshot();
- shot->expectColor(crop, Color::BLACK);
- }
-
- buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
-
- if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
- Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
- } else {
- Transaction().setBuffer(layer, buffer).apply();
- }
-
- {
- SCOPED_TRACE("Buffer Transparent Format");
- auto shot = screenshot();
- shot->expectColor(crop, Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(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();
- {
- SCOPED_TRACE("IDENTITY");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
- {
- SCOPED_TRACE("FLIP_H");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
- Color::WHITE, Color::BLUE);
- }
-
- Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
- {
- SCOPED_TRACE("FLIP_V");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
- Color::RED, Color::GREEN);
- }
-
- Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
- {
- SCOPED_TRACE("ROT_90");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
- Color::WHITE, Color::GREEN);
- }
-
- Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
- {
- SCOPED_TRACE("SCALE");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE, true /* filtered */);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_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()
- .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
- .setFrame(layer, Rect(0, 0, 32, 32))
- .apply();
- {
- SCOPED_TRACE("IDENTITY");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
- {
- SCOPED_TRACE("FLIP_H");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
- {
- SCOPED_TRACE("FLIP_V");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
- {
- SCOPED_TRACE("ROT_90");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
- {
- SCOPED_TRACE("SCALE");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(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;
- Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
-
- auto shot = getScreenCapture();
- // check a 8x8 region inside each color
- auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
- const int32_t halfL = 4;
- return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL);
- };
- const int32_t unit = int32_t(trans / 2);
- shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED);
- shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN);
- shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE);
- shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(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 = getScreenCapture();
- const Rect rect(0, 0, 32, 32);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- const Rect rect(0, 0, 128, 128);
- getScreenCapture()->expectColor(rect, Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
- Transaction()
- .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(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
- // (b/69315456)
- Transaction()
- .setSize(layer, 64, 16)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- {
- SCOPED_TRACE("SCALE_TO_WINDOW");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE, true /* filtered */);
- }
-}
-
-TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-
- sp<IBinder> handle = layer->getHandle();
- ASSERT_TRUE(handle != nullptr);
-
- FrameStats frameStats;
- mClient->getLayerFrameStats(handle, &frameStats);
-
- ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- const Rect crop(8, 8, 24, 24);
-
- Transaction().setCrop_legacy(layer, crop).apply();
- auto shot = getScreenCapture();
- shot->expectColor(crop, Color::RED);
- shot->expectBorder(crop, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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 = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("empty rect");
- Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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();
- getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
- fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
-
- Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply();
-
- Transaction().setBuffer(layer, buffer).apply();
-
- // Partially out of bounds in the negative (upper left) direction
- Transaction().setCrop(layer, Rect(-128, -128, 32, 16)).apply();
- {
- SCOPED_TRACE("out of bounds, negative (upper left) direction");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
- }
-
- // Partially out of bounds in the positive (lower right) direction
- Transaction().setCrop(layer, Rect(0, 16, 128, 128)).apply();
- {
- SCOPED_TRACE("out of bounds, positive (lower right) direction");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
- }
-
- // Fully out of buffer space bounds
- Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
- {
- SCOPED_TRACE("Fully out of bounds");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE);
- shot->expectColor(Rect(0, 16, 64, 64), Color::RED);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- const Point position(32, 32);
- const Rect crop(8, 8, 24, 24);
- Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
- auto shot = getScreenCapture();
- shot->expectColor(crop + position, Color::RED);
- shot->expectBorder(crop + position, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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 Rect frame(32, 32, 64, 64);
- const Rect crop(8, 8, 24, 24);
- Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
- auto shot = getScreenCapture();
- shot->expectColor(frame, Color::RED);
- shot->expectBorder(frame, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // crop_legacy is affected by matrix
- Transaction()
- .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setCrop_legacy(layer, Rect(8, 8, 24, 24))
- .apply();
- auto shot = getScreenCapture();
- shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
- shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- 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();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
- shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- {
- SCOPED_TRACE("resize applied");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
- shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // request setCrop_legacy to be applied with the next resize
- Transaction()
- .setCrop_legacy(layer, Rect(8, 8, 24, 24))
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("waiting for next resize");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
- {
- SCOPED_TRACE("pending crop modified");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- // finally resize
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- {
- SCOPED_TRACE("new crop applied");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
- shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override
- Transaction()
- .setCrop_legacy(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 = getScreenCapture();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
- }
-
- // XXX crop is never latched without other geometry change (b/69315677)
- Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- Transaction().setPosition(layer, 0, 0).apply();
- {
- SCOPED_TRACE("new crop applied");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
- shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_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 frame(8, 8, 24, 24);
-
- Transaction().setFrame(layer, frame).apply();
- auto shot = getScreenCapture();
- shot->expectColor(frame, Color::RED);
- shot->expectBorder(frame, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_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().setFrame(layer, Rect(8, 8, 8, 8)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
-
- // A parentless layer will default to a frame with the same size as the buffer
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
- sp<SurfaceControl> parent, child;
- ASSERT_NO_FATAL_FAILURE(
- parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
- Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
-
- ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
-
- Transaction().reparent(child, parent->getHandle()).apply();
-
- // A layer will default to the frame of its parent
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
- sp<SurfaceControl> parent, child;
- ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
-
- ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
-
- Transaction().reparent(child, parent->getHandle()).apply();
-
- // A layer will default to the frame of its parent
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_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().setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- std::this_thread::sleep_for(500ms);
-
- Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
- shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
- sp<SurfaceControl> parent, child;
- ASSERT_NO_FATAL_FAILURE(
- parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- Transaction().reparent(child, parent->getHandle()).apply();
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
- Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
- Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
- shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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 = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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 = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
-
- {
- SCOPED_TRACE("set buffer 2");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("set buffer 3");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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));
-
- Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
- {
- SCOPED_TRACE("set layer 1 buffer red");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
-
- Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
- {
- SCOPED_TRACE("set layer 2 buffer blue");
- auto shot = getScreenCapture();
- 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 = getScreenCapture();
- 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 = getScreenCapture();
- 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_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
- std::array<sp<GraphicBuffer>, 10> buffers;
-
- size_t idx = 0;
- for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- Color color = colors[idx % colors.size()];
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
- idx++;
- }
-
- // Set each buffer twice. The first time adds it to the cache, the second time tests that the
- // cache is working.
- idx = 0;
- for (auto& buffer : buffers) {
- for (int i = 0; i < 2; i++) {
- Transaction().setBuffer(layer, buffer).apply();
-
- Color color = colors[idx % colors.size()];
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
- idx++;
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
- std::array<sp<GraphicBuffer>, 70> buffers;
-
- size_t idx = 0;
- for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- Color color = colors[idx % colors.size()];
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
- idx++;
- }
-
- // Set each buffer twice. The first time adds it to the cache, the second time tests that the
- // cache is working.
- idx = 0;
- for (auto& buffer : buffers) {
- for (int i = 0; i < 2; i++) {
- Transaction().setBuffer(layer, buffer).apply();
-
- Color color = colors[idx % colors.size()];
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
- idx++;
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
- std::array<sp<GraphicBuffer>, 65> buffers;
-
- size_t idx = 0;
- for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- Color color = colors[idx % colors.size()];
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
- idx++;
- }
-
- // Set each buffer twice. The first time adds it to the cache, the second time tests that the
- // cache is working.
- idx = 0;
- for (auto& buffer : buffers) {
- for (int i = 0; i < 2; i++) {
- Transaction().setBuffer(layer, buffer).apply();
-
- Color color = colors[idx % colors.size()];
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
- if (idx == 0) {
- buffers[0].clear();
- }
- idx++;
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
- .apply();
-
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
- Color::GREEN, true /* filtered */);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
- .apply();
-
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
- Color::BLUE, true /* filtered */);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
- .apply();
-
- getScreenCapture()->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_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
- sp<SurfaceControl> layer;
- Transaction transaction;
- 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;
- if (getBuffer(nullptr, &fence) != NO_ERROR) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
-
- status_t status = fence->wait(1000);
- ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
- std::this_thread::sleep_for(200ms);
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_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 = Fence::NO_FENCE;
-
- Transaction()
- .setBuffer(layer, buffer)
- .setAcquireFence(layer, fence)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, 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)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), 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();
-}
-
-TEST_F(LayerTransactionTest, ReparentToSelf) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- Transaction().reparent(layer, layer->getHandle()).apply();
-
- {
- // We expect the transaction to be silently dropped, but for SurfaceFlinger
- // to still be functioning.
- SCOPED_TRACE("after reparent to self");
- const Rect rect(0, 0, 32, 32);
- auto shot = screenshot();
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-}
-
-class ColorTransformHelper {
-public:
- static void DegammaColorSingle(half& s) {
- if (s <= 0.03928f)
- s = s / 12.92f;
- else
- s = pow((s + 0.055f) / 1.055f, 2.4f);
- }
-
- static void DegammaColor(half3& color) {
- DegammaColorSingle(color.r);
- DegammaColorSingle(color.g);
- DegammaColorSingle(color.b);
- }
-
- static void GammaColorSingle(half& s) {
- if (s <= 0.0031308f) {
- s = s * 12.92f;
- } else {
- s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
- }
- }
-
- static void GammaColor(half3& color) {
- GammaColorSingle(color.r);
- GammaColorSingle(color.g);
- GammaColorSingle(color.b);
- }
-
- static void applyMatrix(half3& color, const mat3& mat) {
- half3 ret = half3(0);
-
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- ret[i] = ret[i] + color[j] * mat[j][i];
- }
- }
- color = ret;
- }
-};
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(colorLayer, mLayerZBase + 1)
- .apply();
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- half3 expected = color;
- mat3 matrix;
- matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
- matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
- matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
-
- // degamma before applying the matrix
- if (mColorManagementUsed) {
- ColorTransformHelper::DegammaColor(expected);
- }
-
- ColorTransformHelper::applyMatrix(expected, matrix);
-
- if (mColorManagementUsed) {
- ColorTransformHelper::GammaColor(expected);
- }
-
- const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
- uint8_t(expected.b * 255), 255};
-
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
-
- Transaction().setColor(colorLayer, color)
- .setColorTransform(colorLayer, matrix, vec3()).apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
- sp<SurfaceControl> parentLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer));
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
-
- Transaction()
- .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(parentLayer, mLayerZBase + 1)
- .apply();
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- half3 expected = color;
- mat3 matrix;
- matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
- matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
- matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
-
- // degamma before applying the matrix
- if (mColorManagementUsed) {
- ColorTransformHelper::DegammaColor(expected);
- }
-
- ColorTransformHelper::applyMatrix(expected, matrix);
-
- if (mColorManagementUsed) {
- ColorTransformHelper::GammaColor(expected);
- }
-
- const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
- uint8_t(expected.b * 255), 255};
-
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
-
- Transaction()
- .setColor(colorLayer, color)
- .setColorTransform(parentLayer, matrix, vec3())
- .apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
- sp<SurfaceControl> parentLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer));
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
-
- Transaction()
- .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(parentLayer, mLayerZBase + 1)
- .apply();
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- half3 expected = color;
- mat3 matrixChild;
- matrixChild[0][0] = 0.3; matrixChild[1][0] = 0.59; matrixChild[2][0] = 0.11;
- matrixChild[0][1] = 0.3; matrixChild[1][1] = 0.59; matrixChild[2][1] = 0.11;
- matrixChild[0][2] = 0.3; matrixChild[1][2] = 0.59; matrixChild[2][2] = 0.11;
- mat3 matrixParent;
- matrixParent[0][0] = 0.2; matrixParent[1][0] = 0.4; matrixParent[2][0] = 0.10;
- matrixParent[0][1] = 0.2; matrixParent[1][1] = 0.4; matrixParent[2][1] = 0.10;
- matrixParent[0][2] = 0.2; matrixParent[1][2] = 0.4; matrixParent[2][2] = 0.10;
-
- // degamma before applying the matrix
- if (mColorManagementUsed) {
- ColorTransformHelper::DegammaColor(expected);
- }
-
- ColorTransformHelper::applyMatrix(expected, matrixChild);
- ColorTransformHelper::applyMatrix(expected, matrixParent);
-
- if (mColorManagementUsed) {
- ColorTransformHelper::GammaColor(expected);
- }
-
- const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
- uint8_t(expected.b * 255), 255};
-
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
-
- Transaction()
- .setColor(colorLayer, color)
- .setColorTransform(parentLayer, matrixParent, vec3())
- .setColorTransform(colorLayer, matrixChild, vec3())
- .apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
- }
-}
-
-struct CallbackData {
- CallbackData() = default;
- CallbackData(nsecs_t time, const sp<Fence>& fence,
- const std::vector<SurfaceControlStats>& stats)
- : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
-
- nsecs_t latchTime;
- sp<Fence> presentFence;
- std::vector<SurfaceControlStats> surfaceControlStats;
-};
-
-class ExpectedResult {
-public:
- enum Transaction {
- NOT_PRESENTED = 0,
- PRESENTED,
- };
-
- enum Buffer {
- NOT_ACQUIRED = 0,
- ACQUIRED,
- };
-
- enum PreviousBuffer {
- NOT_RELEASED = 0,
- RELEASED,
- UNKNOWN,
- };
-
- void reset() {
- mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
- mExpectedSurfaceResults.clear();
- }
-
- void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
- ExpectedResult::Buffer bufferResult = ACQUIRED,
- ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
- mTransactionResult = transactionResult;
- mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
- std::forward_as_tuple(bufferResult, previousBufferResult));
- }
-
- void addSurfaces(ExpectedResult::Transaction transactionResult,
- const std::vector<sp<SurfaceControl>>& layers,
- ExpectedResult::Buffer bufferResult = ACQUIRED,
- ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
- for (const auto& layer : layers) {
- addSurface(transactionResult, layer, bufferResult, previousBufferResult);
- }
- }
-
- void addExpectedPresentTime(nsecs_t expectedPresentTime) {
- mExpectedPresentTime = expectedPresentTime;
- }
-
- void verifyCallbackData(const CallbackData& callbackData) const {
- const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
- if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
- ASSERT_GE(latchTime, 0) << "bad latch time";
- ASSERT_NE(presentFence, nullptr);
- if (mExpectedPresentTime >= 0) {
- ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
- ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
- // if the panel is running at 30 hz, at the worst case, our expected time just
- // misses vsync and we have to wait another 33.3ms
- ASSERT_LE(presentFence->getSignalTime(),
- mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
- }
- } else {
- ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
- ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
- }
-
- ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
- << "wrong number of surfaces";
-
- for (const auto& stats : surfaceControlStats) {
- ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
-
- const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
- ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
- << "unexpected surface control";
- expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
- }
- }
-
-private:
- class ExpectedSurfaceResult {
- public:
- ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
- ExpectedResult::PreviousBuffer previousBufferResult)
- : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
-
- void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
- nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats;
-
- ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
- << "bad acquire time";
- ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
-
- if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
- ASSERT_NE(previousReleaseFence, nullptr)
- << "failed to set release prev buffer fence";
- } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
- ASSERT_EQ(previousReleaseFence, nullptr)
- << "should not have set released prev buffer fence";
- }
- }
-
- private:
- ExpectedResult::Buffer mBufferResult;
- ExpectedResult::PreviousBuffer mPreviousBufferResult;
- };
-
- struct SCHash {
- std::size_t operator()(const sp<SurfaceControl>& sc) const {
- return std::hash<IBinder*>{}(sc->getHandle().get());
- }
- };
- ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
- nsecs_t mExpectedPresentTime = -1;
- std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
-};
-
-class CallbackHelper {
-public:
- static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats) {
- if (!callbackContext) {
- ALOGE("failed to get callback context");
- }
- CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
- std::lock_guard lock(helper->mMutex);
- helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
- helper->mConditionVariable.notify_all();
- }
-
- void getCallbackData(CallbackData* outData) {
- std::unique_lock lock(mMutex);
-
- if (mCallbackDataQueue.empty()) {
- ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
- std::cv_status::timeout)
- << "did not receive callback";
- }
-
- *outData = std::move(mCallbackDataQueue.front());
- mCallbackDataQueue.pop();
- }
-
- void verifyFinalState() {
- // Wait to see if there are extra callbacks
- std::this_thread::sleep_for(500ms);
-
- std::lock_guard lock(mMutex);
- EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
- mCallbackDataQueue = {};
- }
-
- void* getContext() { return static_cast<void*>(this); }
-
- std::mutex mMutex;
- std::condition_variable mConditionVariable;
- std::queue<CallbackData> mCallbackDataQueue;
-};
-
-class LayerCallbackTest : public LayerTransactionTest {
-public:
- virtual sp<SurfaceControl> createBufferStateLayer() {
- return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
- }
-
- static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
- const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
- bool setBackgroundColor = false) {
- if (layer) {
- sp<GraphicBuffer> buffer;
- sp<Fence> fence;
- if (setBuffer) {
- int err = getBuffer(&buffer, &fence);
- if (err != NO_ERROR) {
- return err;
- }
-
- transaction.setBuffer(layer, buffer);
- transaction.setAcquireFence(layer, fence);
- }
-
- if (setBackgroundColor) {
- transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
- ui::Dataspace::UNKNOWN);
- }
- }
-
- transaction.addTransactionCompletedCallback(callbackHelper->function,
- callbackHelper->getContext());
- return NO_ERROR;
- }
-
- static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
- bool finalState = false) {
- CallbackData callbackData;
- ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
- EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
-
- if (finalState) {
- ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
- }
- }
-
- static void waitForCallbacks(CallbackHelper& helper,
- const std::vector<ExpectedResult>& expectedResults,
- bool finalState = false) {
- for (const auto& expectedResult : expectedResults) {
- waitForCallback(helper, expectedResult);
- }
- if (finalState) {
- ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
- }
- }
-};
-
-TEST_F(LayerCallbackTest, BufferColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, true, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoBufferNoColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, false, false);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, BufferNoColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, true, false);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoBufferColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoStateChange) {
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, OffScreen) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeBufferNoColor) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeNoBufferColor) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-TEST_F(LayerCallbackTest, Merge_SameCallback) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback;
- int err = fillTransaction(transaction1, &callback, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, Merge_SameLayer) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, Merge_DifferentClients) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
-
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- for (size_t i = 0; i < 10; i++) {
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
- : ExpectedResult::PreviousBuffer::RELEASED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- for (size_t i = 0; i < 10; i++) {
- ExpectedResult expected;
-
- if (i == 0) {
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- } else {
- int err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- }
-
- transaction.apply();
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- for (size_t i = 0; i < 10; i++) {
- if (i == 0) {
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- } else {
- int err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
- : ExpectedResult::Transaction::NOT_PRESENTED,
- layer,
- (i == 0) ? ExpectedResult::Buffer::ACQUIRED
- : ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
- }
- ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- for (size_t i = 0; i < 10; i++) {
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
- ExpectedResult::Buffer::ACQUIRED,
- (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
- : ExpectedResult::PreviousBuffer::RELEASED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
- ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- for (size_t i = 0; i < 10; i++) {
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
- ExpectedResult::Buffer::ACQUIRED,
- (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
- : ExpectedResult::PreviousBuffer::RELEASED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
- ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
-
- // Normal call to set up test
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
- expected.reset();
-
- // Test
- err = fillTransaction(transaction1, &callback1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.merge(std::move(transaction1)).apply();
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
-
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
-
- // Normal call to set up test
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
- expected.reset();
-
- // Test
- err = fillTransaction(transaction1, &callback1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- std::vector<ExpectedResult> expectedResults(50);
- for (auto& expected : expectedResults) {
- expected.reset();
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- ExpectedResult::PreviousBuffer::UNKNOWN);
-
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
- }
- EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- // Normal call to set up test
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-
- // Test
- std::vector<ExpectedResult> expectedResults(50);
- for (auto& expected : expectedResults) {
- expected.reset();
-
- err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
- }
- EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- // Normal call to set up test
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expectedResult;
- expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
-
- // Test
- std::vector<ExpectedResult> expectedResults(50);
- for (auto& expected : expectedResults) {
- expected.reset();
- expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
- ExpectedResult::Buffer::NOT_ACQUIRED);
-
- err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
- }
- EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected.addExpectedPresentTime(time);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback1;
- int err = fillTransaction(transaction, &callback1, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected1;
- expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected1.addExpectedPresentTime(time);
-
- CallbackHelper callback2;
- err = fillTransaction(transaction, &callback2, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 33ms after the first frame
- time += (33.3 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected2;
- expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- ExpectedResult::PreviousBuffer::RELEASED);
- expected2.addExpectedPresentTime(time);
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback1;
- int err = fillTransaction(transaction, &callback1, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected1;
- expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected1.addExpectedPresentTime(time);
-
- CallbackHelper callback2;
- err = fillTransaction(transaction, &callback2, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 33ms before the previous frame
- time -= (33.3 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected2;
- expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- ExpectedResult::PreviousBuffer::RELEASED);
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the past
- nsecs_t time = systemTime() - (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected.addExpectedPresentTime(systemTime());
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-class LayerUpdateTest : public LayerTransactionTest {
-protected:
- virtual void SetUp() {
- LayerTransactionTest::SetUp();
- ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
- ASSERT_FALSE(display == nullptr);
-
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
-
- // Background surface
- mBGSurfaceControl = createLayer(String8("BG Test Surface"), displayWidth,
- displayHeight, 0);
- ASSERT_TRUE(mBGSurfaceControl != nullptr);
- ASSERT_TRUE(mBGSurfaceControl->isValid());
- fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
-
- // Foreground surface
- mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0);
-
- ASSERT_TRUE(mFGSurfaceControl != nullptr);
- ASSERT_TRUE(mFGSurfaceControl->isValid());
-
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
-
- // Synchronization surface
- mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0);
- ASSERT_TRUE(mSyncSurfaceControl != nullptr);
- ASSERT_TRUE(mSyncSurfaceControl->isValid());
-
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-
- asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
-
- t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
-
- t.setLayer(mFGSurfaceControl, INT32_MAX - 1)
- .setPosition(mFGSurfaceControl, 64, 64)
- .show(mFGSurfaceControl);
-
- t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
- .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2)
- .show(mSyncSurfaceControl);
- });
- }
-
- virtual void TearDown() {
- LayerTransactionTest::TearDown();
- mBGSurfaceControl = 0;
- mFGSurfaceControl = 0;
- mSyncSurfaceControl = 0;
- }
-
- void waitForPostedBuffers() {
- // Since the sync surface is in synchronous mode (i.e. double buffered)
- // posting three buffers to it should ensure that at least two
- // SurfaceFlinger::handlePageFlip calls have been made, which should
- // guaranteed that a buffer posted to another Surface has been retired.
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- }
-
-
- sp<SurfaceControl> mBGSurfaceControl;
- sp<SurfaceControl> mFGSurfaceControl;
-
- // This surface is used to ensure that the buffers posted to
- // mFGSurfaceControl have been picked up by SurfaceFlinger.
- sp<SurfaceControl> mSyncSurfaceControl;
-};
-
-TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
-
- std::unique_ptr<ScreenCapture> sc;
-
- sp<SurfaceControl> relative = createLayer(String8("relativeTestSurface"), 10, 10, 0);
- fillSurfaceRGBA8(relative, 10, 10, 10);
- waitForPostedBuffers();
-
- Transaction{}
- .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
- .setPosition(relative, 64, 64)
- .apply();
-
- {
- // The relative should be on top of the FG control.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(64, 64, 10, 10, 10);
- }
- Transaction{}.detachChildren(mFGSurfaceControl).apply();
-
- {
- // Nothing should change at this point.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(64, 64, 10, 10, 10);
- }
-
- Transaction{}.hide(relative).apply();
-
- {
- // Ensure that the relative was actually hidden, rather than
- // being left in the detached but visible state.
- ScreenCapture::captureScreen(&sc);
- sc->expectFGColor(64, 64);
- }
-}
-
-class GeometryLatchingTest : public LayerUpdateTest {
-protected:
- void EXPECT_INITIAL_STATE(const char* trace) {
- SCOPED_TRACE(trace);
- ScreenCapture::captureScreen(&sc);
- // We find the leading edge of the FG surface.
- sc->expectFGColor(127, 127);
- sc->expectBGColor(128, 128);
- }
-
- void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); }
-
- void unlockFGBuffer() {
- sp<Surface> s = mFGSurfaceControl->getSurface();
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
- waitForPostedBuffers();
- }
-
- void completeFGResize() {
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
- }
- void restoreInitialState() {
- asTransaction([&](Transaction& t) {
- t.setSize(mFGSurfaceControl, 64, 64);
- t.setPosition(mFGSurfaceControl, 64, 64);
- t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
- });
-
- EXPECT_INITIAL_STATE("After restoring initial state");
- }
- std::unique_ptr<ScreenCapture> sc;
-};
-
-class CropLatchingTest : public GeometryLatchingTest {
-protected:
- void EXPECT_CROPPED_STATE(const char* trace) {
- SCOPED_TRACE(trace);
- ScreenCapture::captureScreen(&sc);
- // The edge should be moved back one pixel by our crop.
- sc->expectFGColor(126, 126);
- sc->expectBGColor(127, 127);
- sc->expectBGColor(128, 128);
- }
-
- void EXPECT_RESIZE_STATE(const char* trace) {
- SCOPED_TRACE(trace);
- ScreenCapture::captureScreen(&sc);
- // The FG is now resized too 128,128 at 64,64
- sc->expectFGColor(64, 64);
- sc->expectFGColor(191, 191);
- sc->expectBGColor(192, 192);
- }
-};
-
-TEST_F(LayerUpdateTest, DeferredTransactionTest) {
- std::unique_ptr<ScreenCapture> sc;
- {
- SCOPED_TRACE("before anything");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectFGColor(96, 96);
- sc->expectBGColor(160, 160);
- }
-
- // set up two deferred transactions on different frames
- asTransaction([&](Transaction& t) {
- t.setAlpha(mFGSurfaceControl, 0.75);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber());
- });
-
- asTransaction([&](Transaction& t) {
- t.setPosition(mFGSurfaceControl, 128, 128);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
- });
-
- {
- SCOPED_TRACE("before any trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectFGColor(96, 96);
- sc->expectBGColor(160, 160);
- }
-
- // should trigger the first deferred transaction, but not the second one
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- {
- SCOPED_TRACE("after first trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->checkPixel(96, 96, 162, 63, 96);
- sc->expectBGColor(160, 160);
- }
-
- // should show up immediately since it's not deferred
- asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
-
- // trigger the second deferred transaction
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- {
- SCOPED_TRACE("after second trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectBGColor(96, 96);
- sc->expectFGColor(160, 160);
- }
-}
-
-TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
- std::unique_ptr<ScreenCapture> sc;
-
- sp<SurfaceControl> childNoBuffer =
- createSurface(mClient, "Bufferless child", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- sp<SurfaceControl> childBuffer = createSurface(mClient, "Buffered child", 20, 20,
- PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
- fillSurfaceRGBA8(childBuffer, 200, 200, 200);
- SurfaceComposerClient::Transaction{}
- .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
- .show(childNoBuffer)
- .show(childBuffer)
- .apply(true);
- {
- ScreenCapture::captureScreen(&sc);
- sc->expectChildColor(73, 73);
- sc->expectFGColor(74, 74);
- }
- SurfaceComposerClient::Transaction{}
- .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
- .apply(true);
- {
- ScreenCapture::captureScreen(&sc);
- sc->expectChildColor(73, 73);
- sc->expectChildColor(74, 74);
- }
-}
-
-TEST_F(LayerUpdateTest, MergingTransactions) {
- std::unique_ptr<ScreenCapture> sc;
- {
- SCOPED_TRACE("before move");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(0, 12);
- sc->expectFGColor(75, 75);
- sc->expectBGColor(145, 145);
- }
-
- Transaction t1, t2;
- t1.setPosition(mFGSurfaceControl, 128, 128);
- t2.setPosition(mFGSurfaceControl, 0, 0);
- // We expect that the position update from t2 now
- // overwrites the position update from t1.
- t1.merge(std::move(t2));
- t1.apply();
-
- {
- ScreenCapture::captureScreen(&sc);
- sc->expectFGColor(1, 1);
- }
-}
-
-class ChildLayerTest : public LayerUpdateTest {
-protected:
- void SetUp() override {
- LayerUpdateTest::SetUp();
- mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
- mFGSurfaceControl.get());
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- SCOPED_TRACE("before anything");
- mCapture = screenshot();
- mCapture->expectChildColor(64, 64);
- }
- }
- void TearDown() override {
- LayerUpdateTest::TearDown();
- mChild = 0;
- }
-
- sp<SurfaceControl> mChild;
- std::unique_ptr<ScreenCapture> mCapture;
-};
-
-TEST_F(ChildLayerTest, ChildLayerPositioning) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
-
- {
- mCapture = screenshot();
- // Top left of foreground should now be at 0, 0
- mCapture->expectFGColor(0, 0);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(10, 10);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(20, 20);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerCropping) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
- });
-
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(4, 4);
- mCapture->expectBGColor(5, 5);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerConstraints) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setPosition(mChild, 63, 63);
- });
-
- {
- mCapture = screenshot();
- mCapture->expectFGColor(0, 0);
- // Last pixel in foreground should now be the child.
- mCapture->expectChildColor(63, 63);
- // But the child should be constrained and the next pixel
- // must be the background
- mCapture->expectBGColor(64, 64);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerScaling) {
- asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
-
- // Find the boundary between the parent and child
- {
- mCapture = screenshot();
- mCapture->expectChildColor(9, 9);
- mCapture->expectFGColor(10, 10);
- }
-
- asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); });
-
- // The boundary should be twice as far from the origin now.
- // The pixels from the last test should all be child now
- {
- mCapture = screenshot();
- mCapture->expectChildColor(9, 9);
- mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 19);
- mCapture->expectFGColor(20, 20);
- }
-}
-
-// A child with a scale transform should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
- asTransaction([&](Transaction& t) {
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setPosition(mChild, 0, 0);
- });
-
- // Find the boundary between the parent and child.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 9);
- mCapture->expectFGColor(10, 10);
- }
-
- asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
-
- // The child should fill its parent bounds and be cropped by it.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerAlpha) {
- fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
- fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
- fillSurfaceRGBA8(mChild, 0, 254, 0);
- waitForPostedBuffers();
-
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // Unblended child color
- mCapture->checkPixel(0, 0, 0, 254, 0);
- }
-
- asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); });
-
- {
- mCapture = screenshot();
- // Child and BG blended.
- mCapture->checkPixel(0, 0, 127, 127, 0);
- }
-
- asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); });
-
- {
- mCapture = screenshot();
- // Child and BG blended.
- mCapture->checkPixel(0, 0, 95, 64, 95);
- }
-}
-
-TEST_F(ChildLayerTest, ReparentChildren) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) {
- t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
- });
-
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- // In reparenting we should have exposed the entire foreground surface.
- mCapture->expectFGColor(74, 74);
- // And the child layer should now begin at 10, 10 (since the BG
- // layer is at (0, 0)).
- mCapture->expectBGColor(9, 9);
- mCapture->expectChildColor(10, 10);
- }
-}
-
-TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
- sp<SurfaceControl> mGrandChild =
- createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
- fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
-
- {
- SCOPED_TRACE("Grandchild visible");
- ScreenCapture::captureScreen(&mCapture);
- mCapture->checkPixel(64, 64, 111, 111, 111);
- }
-
- mChild.clear();
-
- {
- SCOPED_TRACE("After destroying child");
- ScreenCapture::captureScreen(&mCapture);
- mCapture->expectFGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) {
- t.reparent(mGrandChild, mFGSurfaceControl->getHandle());
- });
-
- {
- SCOPED_TRACE("After reparenting grandchild");
- ScreenCapture::captureScreen(&mCapture);
- mCapture->checkPixel(64, 64, 111, 111, 111);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenSameClient) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
-
- asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
- asTransaction([&](Transaction& t) { t.hide(mChild); });
-
- // Since the child has the same client as the parent, it will not get
- // detached and will be hidden.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectFGColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
- sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> mChildNewClient =
- createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(mChildNewClient->isValid());
-
- fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
-
- asTransaction([&](Transaction& t) {
- t.hide(mChild);
- t.show(mChildNewClient);
- t.setPosition(mChildNewClient, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
- asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
-
- // Nothing should have changed.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectChildColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
- sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> childNewClient =
- newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(childNewClient != nullptr);
- ASSERT_TRUE(childNewClient->isValid());
-
- fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
- Transaction()
- .hide(mChild)
- .show(childNewClient)
- .setPosition(childNewClient, 10, 10)
- .setPosition(mFGSurfaceControl, 64, 64)
- .apply();
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- Transaction().detachChildren(mFGSurfaceControl).apply();
- Transaction().hide(childNewClient).apply();
-
- // Nothing should have changed.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectChildColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-
- sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
- fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
- 32);
- Transaction()
- .setLayer(newParentSurface, INT32_MAX - 1)
- .show(newParentSurface)
- .setPosition(newParentSurface, 20, 20)
- .reparent(childNewClient, newParentSurface->getHandle())
- .apply();
- {
- mCapture = screenshot();
- // Child is now hidden.
- mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
- }
-}
-TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
- sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> childNewClient =
- newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(childNewClient != nullptr);
- ASSERT_TRUE(childNewClient->isValid());
-
- fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
- Transaction()
- .hide(mChild)
- .show(childNewClient)
- .setPosition(childNewClient, 10, 10)
- .setPosition(mFGSurfaceControl, 64, 64)
- .apply();
-
- {
- mCapture = screenshot();
- Rect rect = Rect(74, 74, 84, 84);
- mCapture->expectBorder(rect, Color{195, 63, 63, 255});
- mCapture->expectColor(rect, Color{200, 200, 200, 255});
- }
-
- Transaction()
- .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber())
- .apply();
- Transaction().detachChildren(mFGSurfaceControl).apply();
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
-
- // BufferLayer can still dequeue buffers even though there's a detached layer with a
- // deferred transaction.
- {
- SCOPED_TRACE("new buffer");
- mCapture = screenshot();
- Rect rect = Rect(74, 74, 84, 84);
- mCapture->expectBorder(rect, Color::RED);
- mCapture->expectColor(rect, Color{200, 200, 200, 255});
- }
-}
-
-TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- // But it's only 10x15.
- mCapture->expectFGColor(10, 15);
- }
-
- asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // We cause scaling by 2.
- t.setSize(mFGSurfaceControl, 128, 128);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 29);
- // And now it should be scaled all the way to 20x30
- mCapture->expectFGColor(20, 30);
- }
-}
-
-// Regression test for b/37673612
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 14);
- // But it's only 10x15.
- mCapture->expectFGColor(10, 15);
- }
- // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
- // the WM specified state size.
- asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- {
- // The child should still be in the same place and not have any strange scaling as in
- // b/37673612.
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectFGColor(10, 10);
- }
-}
-
-// A child with a buffer transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setSize(mChild, 100, 100);
- });
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- mCapture = screenshot();
-
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- // Apply a 90 transform on the buffer.
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- // The child should be cropped by the new parent bounds.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(99, 63);
- mCapture->expectFGColor(100, 63);
- mCapture->expectBGColor(128, 64);
- }
-}
-
-// A child with a scale transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setSize(mChild, 200, 200);
- });
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- mCapture = screenshot();
-
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // Set a scaling by 2.
- t.setSize(mFGSurfaceControl, 128, 128);
- });
-
- // Child should inherit its parents scale but should be cropped by its parent bounds.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(127, 127);
- mCapture->expectBGColor(128, 128);
- }
-}
-
-// Regression test for b/127368943
-// Child should ignore the buffer transform but apply parent scale transform.
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 14);
- mCapture->expectFGColor(10, 15);
- }
-
- // Change the size of the foreground to 128 * 64 so we can test rotation as well.
- asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- t.setSize(mFGSurfaceControl, 128, 64);
- });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
- // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 32, 64);
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- // The child should ignore the buffer transform but apply the 2.0 scale from parent.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(19, 29);
- mCapture->expectFGColor(20, 30);
- }
-}
-
-TEST_F(ChildLayerTest, Bug36858924) {
- // Destroy the child layer
- mChild.clear();
-
- // Now recreate it as hidden
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
-
- // Show the child layer in a deferred transaction
- asTransaction([&](Transaction& t) {
- t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber());
- t.show(mChild);
- });
-
- // Render the foreground surface a few times
- //
- // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
- // frame because SurfaceFlinger would never process the deferred transaction and would therefore
- // never acquire/release the first buffer
- ALOGI("Filling 1");
- fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
- ALOGI("Filling 2");
- fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255);
- ALOGI("Filling 3");
- fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0);
- ALOGI("Filling 4");
- fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
-}
-
-TEST_F(ChildLayerTest, Reparent) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
-
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- // In reparenting we should have exposed the entire foreground surface.
- mCapture->expectFGColor(74, 74);
- // And the child layer should now begin at 10, 10 (since the BG
- // layer is at (0, 0)).
- mCapture->expectBGColor(9, 9);
- mCapture->expectChildColor(10, 10);
- }
-}
-
-TEST_F(ChildLayerTest, ReparentToNoParent) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
- asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
- {
- mCapture = screenshot();
- // The surface should now be offscreen.
- mCapture->expectFGColor(64, 64);
- mCapture->expectFGColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, ReparentFromNoParent) {
- sp<SurfaceControl> newSurface = createLayer(String8("New Surface"), 10, 10, 0);
- ASSERT_TRUE(newSurface != nullptr);
- ASSERT_TRUE(newSurface->isValid());
-
- fillSurfaceRGBA8(newSurface, 63, 195, 63);
- asTransaction([&](Transaction& t) {
- t.hide(mChild);
- t.show(newSurface);
- t.setPosition(newSurface, 10, 10);
- t.setLayer(newSurface, INT32_MAX - 2);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // At 10, 10 we should see the new surface
- mCapture->checkPixel(10, 10, 63, 195, 63);
- }
-
- asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
-
- {
- mCapture = screenshot();
- // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
- // mFGSurface, putting it at 74, 74.
- mCapture->expectFGColor(64, 64);
- mCapture->checkPixel(74, 74, 63, 195, 63);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, NestedChildren) {
- sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
- fillSurfaceRGBA8(grandchild, 50, 50, 50);
-
- {
- mCapture = screenshot();
- // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
- // which begins at 64, 64
- mCapture->checkPixel(64, 64, 50, 50, 50);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
- sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 128, 128, 0);
- fillSurfaceRGBA8(relative, 255, 255, 255);
-
- Transaction t;
- t.setLayer(relative, INT32_MAX)
- .setRelativeLayer(mChild, relative->getHandle(), 1)
- .setPosition(mFGSurfaceControl, 0, 0)
- .apply(true);
-
- // We expect that the child should have been elevated above our
- // INT_MAX layer even though it's not a child of it.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 9);
- mCapture->checkPixel(10, 10, 255, 255, 255);
- }
-}
-
-class BoundlessLayerTest : public LayerUpdateTest {
-protected:
- std::unique_ptr<ScreenCapture> mCapture;
-};
-
-// Verify setting a size on a buffer layer has no effect.
-TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
- sp<SurfaceControl> bufferLayer =
- createSurface(mClient, "BufferLayer", 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
- mFGSurfaceControl.get());
- ASSERT_TRUE(bufferLayer->isValid());
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
- asTransaction([&](Transaction& t) { t.show(bufferLayer); });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
- // Buffer layer should not extend past buffer bounds
- mCapture->expectFGColor(95, 95);
- }
-}
-
-// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
-// which will crop the color layer.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
-// a crop which will be used to crop the color layer.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
- sp<SurfaceControl> cropLayer = createSurface(mClient, "CropLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(cropLayer->isValid());
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(cropLayer);
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // 5 pixels from the foreground we should see the child surface
- mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
- // 10 pixels from the foreground we should be back to the foreground surface
- mCapture->expectFGColor(74, 74);
- }
-}
-
-// Verify for boundless layer with no children, their transforms have no effect.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setPosition(colorLayer, 320, 320);
- t.setMatrix(colorLayer, 2, 0, 0, 2);
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify for boundless layer with children, their transforms have an effect.
-TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
- sp<SurfaceControl> boundlessLayerRightShift =
- createSurface(mClient, "BoundlessLayerRightShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(boundlessLayerRightShift->isValid());
- sp<SurfaceControl> boundlessLayerDownShift =
- createSurface(mClient, "BoundlessLayerLeftShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, boundlessLayerRightShift.get());
- ASSERT_TRUE(boundlessLayerDownShift->isValid());
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setPosition(boundlessLayerRightShift, 32, 0);
- t.show(boundlessLayerRightShift);
- t.setPosition(boundlessLayerDownShift, 0, 32);
- t.show(boundlessLayerDownShift);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify child layers do not get clipped if they temporarily move into the negative
-// coordinate space as the result of an intermediate transformation.
-TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
- sp<SurfaceControl> boundlessLayer =
- mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(boundlessLayer != nullptr);
- ASSERT_TRUE(boundlessLayer->isValid());
- sp<SurfaceControl> colorLayer =
- mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
- ASSERT_TRUE(colorLayer != nullptr);
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- // shift child layer off bounds. If this layer was not boundless, we will
- // expect the child layer to be cropped.
- t.setPosition(boundlessLayer, 32, 32);
- t.show(boundlessLayer);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
- // undo shift by parent
- t.setPosition(colorLayer, -32, -32);
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify for boundless root layers with children, their transforms have an effect.
-TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
- sp<SurfaceControl> rootBoundlessLayer = createSurface(mClient, "RootBoundlessLayer", 0, 0,
- PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
- ASSERT_TRUE(rootBoundlessLayer->isValid());
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
-
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
- t.setPosition(rootBoundlessLayer, 32, 32);
- t.show(rootBoundlessLayer);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- t.hide(mFGSurfaceControl);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Top left of foreground must now be visible
- mCapture->expectBGColor(31, 31);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(97, 97);
- }
-}
-
-class ScreenCaptureTest : public LayerUpdateTest {
-protected:
- std::unique_ptr<ScreenCapture> mCapture;
-};
-
-TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
- auto bgHandle = mBGSurfaceControl->getHandle();
- ScreenCapture::captureLayers(&mCapture, bgHandle);
- mCapture->expectBGColor(0, 0);
- // Doesn't capture FG layer which is at 64, 64
- mCapture->expectBGColor(64, 64);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(child).apply(true);
-
- // Captures mFGSurfaceControl layer and its child.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(child).apply(true);
-
- // Captures mFGSurfaceControl's child
- ScreenCapture::captureChildLayers(&mCapture, fgHandle);
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerExclude) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child2, 200, 0, 200);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- .show(child2)
- .setLayer(child, 1)
- .setLayer(child2, 2)
- .apply(true);
-
- // Child2 would be visible but its excluded, so we should see child1 color instead.
- ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->checkPixel(0, 0, 200, 200, 200);
-}
-
-// Like the last test but verifies that children are also exclude.
-TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child2, 200, 0, 200);
- sp<SurfaceControl> child3 = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, child2.get());
- fillSurfaceRGBA8(child2, 200, 0, 200);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- .show(child2)
- .show(child3)
- .setLayer(child, 1)
- .setLayer(child2, 2)
- .apply(true);
-
- // Child2 would be visible but its excluded, so we should see child1 color instead.
- ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->checkPixel(0, 0, 200, 200, 200);
-}
-
-TEST_F(ScreenCaptureTest, CaptureTransparent) {
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(child).apply(true);
-
- auto childHandle = child->getHandle();
-
- // Captures child
- ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
- mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
- // Area outside of child's bounds is transparent.
- mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
-}
-
-TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- ASSERT_NE(nullptr, child.get()) << "failed to create surface";
- sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 10, 10, 0);
- fillSurfaceRGBA8(child, 200, 200, 200);
- fillSurfaceRGBA8(relative, 100, 100, 100);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- // Set relative layer above fg layer so should be shown above when computing all layers.
- .setRelativeLayer(relative, fgHandle, 1)
- .show(relative)
- .apply(true);
-
- // Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- fillSurfaceRGBA8(relative, 100, 100, 100);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- // Set relative layer below fg layer but relative to child layer so it should be shown
- // above child layer.
- .setLayer(relative, -1)
- .setRelativeLayer(relative, child->getHandle(), 1)
- .show(relative)
- .apply(true);
-
- // Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
- // relative value should be taken into account, placing it above child layer.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- // Relative layer is showing on top of child layer
- mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
-}
-
-// In the following tests we verify successful skipping of a parent layer,
-// so we use the same verification logic and only change how we mutate
-// the parent layer to verify that various properties are ignored.
-class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
-public:
- void SetUp() override {
- LayerUpdateTest::SetUp();
-
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
- mFGSurfaceControl.get());
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(mChild).apply(true);
- }
-
- void verify(std::function<void()> verifyStartingState) {
- // Verify starting state before a screenshot is taken.
- verifyStartingState();
-
- // Verify child layer does not inherit any of the properties of its
- // parent when its screenshot is captured.
- auto fgHandle = mFGSurfaceControl->getHandle();
- ScreenCapture::captureChildLayers(&mCapture, fgHandle);
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->expectChildColor(0, 0);
-
- // Verify all assumptions are still true after the screenshot is taken.
- verifyStartingState();
- }
-
- std::unique_ptr<ScreenCapture> mCapture;
- sp<SurfaceControl> mChild;
-};
-
-// Regression test b/76099859
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
-
- SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
-
- // Even though the parent is hidden we should still capture the child.
-
- // Before and after reparenting, verify child is properly hidden
- // when rendering full-screen.
- verify([&] { screenshot()->expectBGColor(64, 64); });
-}
-
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
- SurfaceComposerClient::Transaction()
- .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
- .apply(true);
-
- // Even though the parent is cropped out we should still capture the child.
-
- // Before and after reparenting, verify child is cropped by parent.
- verify([&] { screenshot()->expectBGColor(65, 65); });
-}
-
-// Regression test b/124372894
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
- SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
-
- // We should not inherit the parent scaling.
-
- // Before and after reparenting, verify child is properly scaled.
- verify([&] { screenshot()->expectChildColor(80, 80); });
-}
-
-
-TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
- PIXEL_FORMAT_RGBA_8888, 0, child.get());
-
- fillSurfaceRGBA8(grandchild, 50, 50, 50);
- SurfaceComposerClient::Transaction()
- .show(child)
- .setPosition(grandchild, 5, 5)
- .show(grandchild)
- .apply(true);
-
- // Captures mFGSurfaceControl, its child, and the grandchild.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- mCapture->expectChildColor(0, 0);
- mCapture->checkPixel(5, 5, 50, 50, 50);
-}
-
-TEST_F(ScreenCaptureTest, CaptureChildOnly) {
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- auto childHandle = child->getHandle();
-
- SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
-
- // Captures only the child layer, and not the parent.
- ScreenCapture::captureLayers(&mCapture, childHandle);
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 9);
-}
-
-TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- auto childHandle = child->getHandle();
-
- sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
- PIXEL_FORMAT_RGBA_8888, 0, child.get());
- fillSurfaceRGBA8(grandchild, 50, 50, 50);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- .setPosition(grandchild, 5, 5)
- .show(grandchild)
- .apply(true);
-
- auto grandchildHandle = grandchild->getHandle();
-
- // Captures only the grandchild.
- ScreenCapture::captureLayers(&mCapture, grandchildHandle);
- mCapture->checkPixel(0, 0, 50, 50, 50);
- mCapture->checkPixel(4, 4, 50, 50, 50);
-}
-
-TEST_F(ScreenCaptureTest, CaptureCrop) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
- sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
- PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
-
- 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)
- .show(redLayer)
- .show(blueLayer)
- .apply(true);
-
- auto redLayerHandle = redLayer->getHandle();
-
- // Capturing full screen should have both red and blue are visible.
- ScreenCapture::captureLayers(&mCapture, redLayerHandle);
- mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
- // red area below the blue area
- mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
- // red area to the right of the blue area
- mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
-
- const Rect crop = Rect(0, 0, 30, 30);
- ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
- // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
- // area visible.
- mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
- mCapture->checkPixel(30, 30, 0, 0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureSize) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
- sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
- PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
-
- 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)
- .show(redLayer)
- .show(blueLayer)
- .apply(true);
-
- auto redLayerHandle = redLayer->getHandle();
-
- // Capturing full screen should have both red and blue are visible.
- ScreenCapture::captureLayers(&mCapture, redLayerHandle);
- mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
- // red area below the blue area
- mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
- // red area to the right of the blue area
- mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
-
- ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
- // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
- mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
- // red area below the blue area
- mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED);
- // red area to the right of the blue area
- mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED);
- mCapture->checkPixel(30, 30, 0, 0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
-
- auto redLayerHandle = redLayer->getHandle();
- redLayer.clear();
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
-
- // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
-}
-
-
-class DereferenceSurfaceControlTest : public LayerTransactionTest {
-protected:
- void SetUp() override {
- LayerTransactionTest::SetUp();
- bgLayer = createLayer("BG layer", 20, 20);
- fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
- fgLayer = createLayer("FG layer", 20, 20);
- fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
- Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
- {
- SCOPED_TRACE("before anything");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
- }
- }
- void TearDown() override {
- LayerTransactionTest::TearDown();
- bgLayer = 0;
- fgLayer = 0;
- }
-
- sp<SurfaceControl> bgLayer;
- sp<SurfaceControl> fgLayer;
-};
-
-TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
- fgLayer = nullptr;
- {
- SCOPED_TRACE("after setting null");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
- }
-}
-
-TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
- auto transaction = Transaction().show(fgLayer);
- fgLayer = nullptr;
- {
- SCOPED_TRACE("after setting null");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
- }
-}
-
-class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
-protected:
- virtual void SetUp() {
- LayerTransactionTest::SetUp();
- ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
- mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
-
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&mProducer, &consumer);
- consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
- }
-
- virtual void TearDown() {
- SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
- LayerTransactionTest::TearDown();
- mColorLayer = 0;
- }
-
- void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
- mVirtualDisplay =
- SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
- asTransaction([&](Transaction& t) {
- t.setDisplaySurface(mVirtualDisplay, mProducer);
- t.setDisplayLayerStack(mVirtualDisplay, layerStack);
- t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
- Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
- });
- }
-
- void createColorLayer(uint32_t layerStack) {
- mColorLayer =
- createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
- ASSERT_TRUE(mColorLayer != nullptr);
- ASSERT_TRUE(mColorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setLayerStack(mColorLayer, layerStack);
- t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
- t.setLayer(mColorLayer, INT32_MAX - 2);
- t.setColor(mColorLayer,
- half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
- mExpectedColor.b / 255.0f});
- t.show(mColorLayer);
- });
- }
-
- DisplayInfo mMainDisplayInfo;
- sp<IBinder> mMainDisplay;
- sp<IBinder> mVirtualDisplay;
- sp<IGraphicBufferProducer> mProducer;
- sp<SurfaceControl> mColorLayer;
- Color mExpectedColor = {63, 63, 195, 255};
-};
-
-TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
- createColorLayer(1 /* layerStack */);
-
- asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
-
- // Verify color layer does not render on main display.
- std::unique_ptr<ScreenCapture> sc;
- ScreenCapture::captureScreen(&sc, mMainDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
- sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-
- // Verify color layer renders correctly on virtual display.
- ScreenCapture::captureScreen(&sc, mVirtualDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
- sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 0});
-}
-
-TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
- // Create a display and set its layer stack to the main display's layer stack so
- // the contents of the main display are mirrored on to the virtual display.
-
- // Assumption here is that the new mirrored display has the same viewport as the
- // primary display that it is mirroring.
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
- createColorLayer(0 /* layerStack */);
-
- asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
-
- // Verify color layer renders correctly on main display and it is mirrored on the
- // virtual display.
- std::unique_ptr<ScreenCapture> sc;
- ScreenCapture::captureScreen(&sc, mMainDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
- sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-
- ScreenCapture::captureScreen(&sc, mVirtualDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
- sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-}
-
-class DisplayActiveConfigTest : public ::testing::Test {
-protected:
- void SetUp() override {
- mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
- SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &mDisplayconfigs);
- EXPECT_GT(mDisplayconfigs.size(), 0);
-
- // set display power to on to make sure config can be changed
- SurfaceComposerClient::setDisplayPowerMode(mDisplayToken, HWC_POWER_MODE_NORMAL);
- }
-
- sp<IBinder> mDisplayToken;
- Vector<DisplayInfo> mDisplayconfigs;
-};
-
-TEST_F(DisplayActiveConfigTest, allConfigsAllowed) {
- std::vector<int32_t> allowedConfigs;
-
- // Add all configs to the allowed configs
- for (int i = 0; i < mDisplayconfigs.size(); i++) {
- allowedConfigs.push_back(i);
- }
-
- status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
- EXPECT_EQ(res, NO_ERROR);
-
- std::vector<int32_t> outConfigs;
- res = SurfaceComposerClient::getAllowedDisplayConfigs(mDisplayToken, &outConfigs);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(allowedConfigs, outConfigs);
-}
-
-TEST_F(DisplayActiveConfigTest, changeAllowedConfig) {
- // we need at least 2 configs available for this test
- if (mDisplayconfigs.size() <= 1) return;
-
- int activeConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
-
- // We want to set the allowed config to everything but the active config
- std::vector<int32_t> allowedConfigs;
- for (int i = 0; i < mDisplayconfigs.size(); i++) {
- if (i != activeConfig) {
- allowedConfigs.push_back(i);
- }
- }
-
- status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
- EXPECT_EQ(res, NO_ERROR);
-
- // Allow some time for the config change
- std::this_thread::sleep_for(200ms);
-
- int newActiveConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
- EXPECT_NE(activeConfig, newActiveConfig);
-
- // Make sure the new config is part of allowed config
- EXPECT_TRUE(std::find(allowedConfigs.begin(), allowedConfigs.end(), newActiveConfig) !=
- allowedConfigs.end());
-}
-
-class RelativeZTest : public LayerTransactionTest {
-protected:
- virtual void SetUp() {
- LayerTransactionTest::SetUp();
- ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
- ASSERT_FALSE(display == nullptr);
-
- // Back layer
- mBackgroundLayer = createColorLayer("Background layer", Color::RED);
-
- // Front layer
- mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
-
- asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
- t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
- t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
- });
- }
-
- virtual void TearDown() {
- LayerTransactionTest::TearDown();
- mBackgroundLayer = 0;
- mForegroundLayer = 0;
- }
-
- sp<SurfaceControl> mBackgroundLayer;
- sp<SurfaceControl> mForegroundLayer;
-};
-
-// When a layer is reparented offscreen, remove relative z order if the relative parent
-// is still onscreen so that the layer is not drawn.
-TEST_F(RelativeZTest, LayerRemoved) {
- std::unique_ptr<ScreenCapture> sc;
-
- // Background layer (RED)
- // Child layer (WHITE) (relative to foregroud layer)
- // Foregroud layer (GREEN)
- sp<SurfaceControl> childLayer =
- createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
-
- Transaction{}
- .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
- .show(childLayer)
- .apply();
-
- {
- // The childLayer should be in front of the FG control.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
- }
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- Transaction{}.reparent(childLayer, nullptr).apply();
-
- // Background layer (RED)
- // Child layer (WHITE)
- // Foregroud layer (GREEN)
- Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
-
- {
- // The relative z info for child layer should be reset, leaving FG control on top.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
- }
-}
-
-// When a layer is reparented offscreen, preseve relative z order if the relative parent
-// is also offscreen. Regression test b/132613412
-TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) {
- std::unique_ptr<ScreenCapture> sc;
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- // child level 1 (WHITE)
- // child level 2a (BLUE)
- // child level 3 (GREEN) (relative to child level 2b)
- // child level 2b (BLACK)
- sp<SurfaceControl> childLevel1 =
- createColorLayer("child level 1", Color::WHITE, mForegroundLayer.get());
- sp<SurfaceControl> childLevel2a =
- createColorLayer("child level 2a", Color::BLUE, childLevel1.get());
- sp<SurfaceControl> childLevel2b =
- createColorLayer("child level 2b", Color::BLACK, childLevel1.get());
- sp<SurfaceControl> childLevel3 =
- createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
-
- Transaction{}
- .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
- .show(childLevel2a)
- .show(childLevel2b)
- .show(childLevel3)
- .apply();
-
- {
- // The childLevel3 should be in front of childLevel2b.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
- }
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- Transaction{}.reparent(childLevel1, nullptr).apply();
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- // child level 1 (WHITE)
- // child level 2 back (BLUE)
- // child level 3 (GREEN) (relative to child level 2b)
- // child level 2 front (BLACK)
- Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
-
- {
- // Nothing should change at this point since relative z info was preserved.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
- }
-}
-
-// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
-// the dropped buffer's damage region into the next buffer's damage region. If
-// we don't do this, we'll report an incorrect damage region to hardware
-// composer, resulting in broken rendering. This test checks the BufferQueue
-// case.
-//
-// Unfortunately, we don't currently have a way to inspect the damage region
-// SurfaceFlinger sends to hardware composer from a test, so this test requires
-// the dev to manually watch the device's screen during the test to spot broken
-// rendering. Because the results can't be automatically verified, this test is
-// marked disabled.
-TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
- const int width = mDisplayWidth;
- const int height = mDisplayHeight;
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
- const auto producer = layer->getIGraphicBufferProducer();
- const sp<IProducerListener> dummyListener(new DummyProducerListener);
- IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
- ASSERT_EQ(OK,
- producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
-
- std::map<int, sp<GraphicBuffer>> slotMap;
- auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
- ASSERT_NE(nullptr, buf);
- const auto iter = slotMap.find(slot);
- ASSERT_NE(slotMap.end(), iter);
- *buf = iter->second;
- };
-
- auto dequeue = [&](int* outSlot) {
- ASSERT_NE(nullptr, outSlot);
- *outSlot = -1;
- int slot;
- sp<Fence> fence;
- uint64_t age;
- FrameEventHistoryDelta timestamps;
- const status_t dequeueResult =
- producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- &age, ×tamps);
- if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
- sp<GraphicBuffer> newBuf;
- ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
- ASSERT_NE(nullptr, newBuf.get());
- slotMap[slot] = newBuf;
- } else {
- ASSERT_EQ(OK, dequeueResult);
- }
- *outSlot = slot;
- };
-
- auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
- IGraphicBufferProducer::QueueBufferInput input(
- /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
- /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
- /*transform=*/0, Fence::NO_FENCE);
- input.setSurfaceDamage(damage);
- IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
- };
-
- auto fillAndPostBuffers = [&](const Color& color) {
- int slot1;
- ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
- int slot2;
- ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
-
- sp<GraphicBuffer> buf1;
- ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
- sp<GraphicBuffer> buf2;
- ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
- fillGraphicBufferColor(buf1, Rect(width, height), color);
- fillGraphicBufferColor(buf2, Rect(width, height), color);
-
- const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
- ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
- ASSERT_NO_FATAL_FAILURE(
- queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
- displayTime));
- };
-
- const auto startTime = systemTime();
- const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
- int colorIndex = 0;
- while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
- ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
- std::this_thread::sleep_for(1s);
- }
-
- ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2feff45..2861013 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -10,32 +10,38 @@
],
shared_libs: [
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer@2.1-resources",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hardware.power@1.3",
"libbase",
"libbinder",
"libcutils",
"libfmq",
"libgui",
- "libhardware",
"libhidlbase",
"liblayers_proto",
"liblog",
"libnativewindow",
"libsync",
- "libtimestats_proto",
+ "libtimestats",
"libui",
"libutils",
],
static_libs: [
+ "libcompositionengine",
"libgmock",
+ "libperfetto_client_experimental",
"librenderengine",
"libtrace_proto",
],
header_libs: [
- "android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.1-hal",
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ "android.hardware.graphics.composer@2.4-hal",
"libsurfaceflinger_headers",
],
}
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index eeb6efe..5cbf2ef 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeComposer"
@@ -146,6 +150,7 @@
FakeComposerClient::FakeComposerClient()
: mEventCallback(nullptr),
+ mEventCallback_2_4(nullptr),
mCurrentConfig(NULL_DISPLAY_CONFIG),
mVsyncEnabled(false),
mLayers(),
@@ -165,6 +170,9 @@
void FakeComposerClient::registerEventCallback(EventCallback* callback) {
ALOGV("registerEventCallback");
+ LOG_FATAL_IF(mEventCallback_2_4 != nullptr,
+ "already registered using registerEventCallback_2_4");
+
mEventCallback = callback;
if (mEventCallback) {
mEventCallback->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
@@ -179,12 +187,16 @@
void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
if (mEventCallback) {
mEventCallback->onHotplug(display, state);
+ } else if (mEventCallback_2_4) {
+ mEventCallback_2_4->onHotplug(display, state);
}
}
void FakeComposerClient::refreshDisplay(Display display) {
if (mEventCallback) {
mEventCallback->onRefresh(display);
+ } else if (mEventCallback_2_4) {
+ mEventCallback_2_4->onRefresh(display);
}
}
@@ -193,33 +205,37 @@
return 1;
}
-Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
- PixelFormat* /*format*/, Display* /*outDisplay*/) {
+V2_1::Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
+ V1_0::PixelFormat* /*format*/,
+ Display* /*outDisplay*/) {
ALOGV("createVirtualDisplay");
- return Error::NONE;
+ return V2_1::Error::NONE;
}
-Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
+V2_1::Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
ALOGV("destroyVirtualDisplay");
- return Error::NONE;
+ return V2_1::Error::NONE;
}
-Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
+V2_1::Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
ALOGV("createLayer");
*outLayer = mLayers.size();
auto newLayer = std::make_unique<LayerImpl>();
mLayers.push_back(std::move(newLayer));
- return Error::NONE;
+ return V2_1::Error::NONE;
}
-Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
+V2_1::Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
ALOGV("destroyLayer");
mLayers[layer]->mValid = false;
- return Error::NONE;
+ return V2_1::Error::NONE;
}
-Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) {
+V2_1::Error FakeComposerClient::getActiveConfig(Display display, Config* outConfig) {
ALOGV("getActiveConfig");
+ if (mMockHal) {
+ return mMockHal->getActiveConfig(display, outConfig);
+ }
// TODO Assert outConfig != nullptr
@@ -227,30 +243,480 @@
// IComposerClient::getActiveConfig, but returning BAD_CONFIG
// seems to not fit SurfaceFlinger plans. See version 2 below.
// if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
- // return Error::BAD_CONFIG;
+ // return V2_1::Error::BAD_CONFIG;
// }
//*outConfig = mCurrentConfig;
*outConfig = 1; // Very special config for you my friend
- return Error::NONE;
+ return V2_1::Error::NONE;
}
-Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
- uint32_t /*height*/, PixelFormat /*format*/,
- Dataspace /*dataspace*/) {
+V2_1::Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
+ uint32_t /*height*/,
+ V1_0::PixelFormat /*format*/,
+ V1_0::Dataspace /*dataspace*/) {
ALOGV("getClientTargetSupport");
- return Error::NONE;
+ return V2_1::Error::NONE;
}
-Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) {
+V2_1::Error FakeComposerClient::getColorModes(Display /*display*/,
+ hidl_vec<V1_0::ColorMode>* /*outModes*/) {
ALOGV("getColorModes");
- return Error::NONE;
+ return V2_1::Error::NONE;
}
-Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute,
- int32_t* outValue) {
+V2_1::Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
+ V2_1::IComposerClient::Attribute attribute,
+ int32_t* outValue) {
+ auto tmpError =
+ getDisplayAttribute_2_4(display, config,
+ static_cast<IComposerClient::Attribute>(attribute), outValue);
+ return static_cast<V2_1::Error>(tmpError);
+}
+
+V2_1::Error FakeComposerClient::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
+ ALOGV("getDisplayConfigs");
+ if (mMockHal) {
+ return mMockHal->getDisplayConfigs(display, outConfigs);
+ }
+
+ // TODO assert display == 1, outConfigs != nullptr
+
+ outConfigs->resize(1);
+ (*outConfigs)[0] = 1;
+
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
+ ALOGV("getDisplayName");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getDisplayType(Display /*display*/,
+ IComposerClient::DisplayType* outType) {
+ ALOGV("getDisplayType");
+ // TODO: This setting nothing on the output had no effect on initial trials. Is first display
+ // assumed to be physical?
+ *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
+ ALOGV("getDozeSupport");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getHdrCapabilities(Display /*display*/,
+ hidl_vec<V1_0::Hdr>* /*outTypes*/,
+ float* /*outMaxLuminance*/,
+ float* /*outMaxAverageLuminance*/,
+ float* /*outMinLuminance*/) {
+ ALOGV("getHdrCapabilities");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setActiveConfig(Display display, Config config) {
+ ALOGV("setActiveConfig");
+ if (mMockHal) {
+ return mMockHal->setActiveConfig(display, config);
+ }
+ mCurrentConfig = config;
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setColorMode(Display /*display*/, V1_0::ColorMode /*mode*/) {
+ ALOGV("setColorMode");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setPowerMode(Display /*display*/,
+ V2_1::IComposerClient::PowerMode /*mode*/) {
+ ALOGV("setPowerMode");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setVsyncEnabled(Display /*display*/,
+ IComposerClient::Vsync enabled) {
+ mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
+ ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
+ int32_t /*hint*/) {
+ ALOGV("setColorTransform");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
+ int32_t /*acquireFence*/, int32_t /*dataspace*/,
+ const std::vector<hwc_rect_t>& /*damage*/) {
+ ALOGV("setClientTarget");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
+ int32_t /*releaseFence*/) {
+ ALOGV("setOutputBuffer");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::validateDisplay(
+ Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
+ std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
+ uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
+ std::vector<uint32_t>* /*outRequestMasks*/) {
+ ALOGV("validateDisplay");
+ // TODO: Assume touching nothing means All Korrekt!
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
+ ALOGV("acceptDisplayChanges");
+ // Didn't ask for changes because software is omnipotent.
+ return V2_1::Error::NONE;
+}
+
+bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
+ return a->z <= b->z;
+}
+
+V2_1::Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
+ std::vector<Layer>* /*outLayers*/,
+ std::vector<int32_t>* /*outReleaseFences*/) {
+ ALOGV("presentDisplay");
+ // TODO Leaving layers and their fences out for now. Doing so
+ // means that we've already processed everything. Important to
+ // test that the fences are respected, though. (How?)
+
+ std::unique_ptr<Frame> newFrame(new Frame);
+ for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
+ const LayerImpl& layerImpl = *mLayers[layer];
+
+ if (!layerImpl.mValid) continue;
+
+ auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
+ newFrame->rectangles.push_back(std::move(rect));
+ }
+ std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
+ {
+ Mutex::Autolock _l(mStateMutex);
+ mFrames.push_back(std::move(newFrame));
+ mFramesAvailable.broadcast();
+ }
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
+ int32_t /*x*/, int32_t /*y*/) {
+ ALOGV("setLayerCursorPosition");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer,
+ buffer_handle_t buffer, int32_t acquireFence) {
+ ALOGV("setLayerBuffer");
+ LayerImpl& l = getLayerImpl(layer);
+ if (buffer != l.mRenderState.mBuffer) {
+ l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
+ }
+ l.mRenderState.mBuffer = buffer;
+ l.mRenderState.mAcquireFence = acquireFence;
+
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
+ const std::vector<hwc_rect_t>& /*damage*/) {
+ ALOGV("setLayerSurfaceDamage");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
+ ALOGV("setLayerBlendMode");
+ getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
+ IComposerClient::Color color) {
+ ALOGV("setLayerColor");
+ getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
+ getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
+ getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
+ getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
+ int32_t /*type*/) {
+ ALOGV("setLayerCompositionType");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
+ int32_t /*dataspace*/) {
+ ALOGV("setLayerDataspace");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
+ const hwc_rect_t& frame) {
+ ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
+ frame.bottom);
+ getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
+ ALOGV("setLayerPlaneAlpha");
+ getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
+ buffer_handle_t /*stream*/) {
+ ALOGV("setLayerSidebandStream");
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
+ const hwc_frect_t& crop) {
+ ALOGV("setLayerSourceCrop");
+ getLayerImpl(layer).mRenderState.mSourceCrop = crop;
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer,
+ int32_t transform) {
+ ALOGV("setLayerTransform");
+ getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
+ const std::vector<hwc_rect_t>& visible) {
+ ALOGV("setLayerVisibleRegion");
+ getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
+ return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
+ ALOGV("setLayerZOrder");
+ getLayerImpl(layer).mZ = z;
+ return V2_1::Error::NONE;
+}
+
+// Composer 2.2
+V2_1::Error FakeComposerClient::getPerFrameMetadataKeys(
+ Display /*display*/, std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerPerFrameMetadata(
+ Display /*display*/, Layer /*layer*/,
+ const std::vector<V2_2::IComposerClient::PerFrameMetadata>& /*metadata*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getReadbackBufferAttributes(
+ Display /*display*/, graphics::common::V1_1::PixelFormat* /*outFormat*/,
+ graphics::common::V1_1::Dataspace* /*outDataspace*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setReadbackBuffer(Display /*display*/,
+ const native_handle_t* /*bufferHandle*/,
+ android::base::unique_fd /*fenceFd*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getReadbackBufferFence(Display /*display*/,
+ android::base::unique_fd* /*outFenceFd*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::createVirtualDisplay_2_2(
+ uint32_t /*width*/, uint32_t /*height*/, graphics::common::V1_1::PixelFormat* /*format*/,
+ Display* /*outDisplay*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+V2_1::Error FakeComposerClient::getClientTargetSupport_2_2(
+ Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
+ graphics::common::V1_1::PixelFormat /*format*/,
+ graphics::common::V1_1::Dataspace /*dataspace*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setPowerMode_2_2(Display /*display*/,
+ V2_2::IComposerClient::PowerMode /*mode*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerFloatColor(Display /*display*/, Layer /*layer*/,
+ V2_2::IComposerClient::FloatColor /*color*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getColorModes_2_2(
+ Display /*display*/, hidl_vec<graphics::common::V1_1::ColorMode>* /*outModes*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getRenderIntents(
+ Display /*display*/, graphics::common::V1_1::ColorMode /*mode*/,
+ std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setColorMode_2_2(Display /*display*/,
+ graphics::common::V1_1::ColorMode /*mode*/,
+ graphics::common::V1_1::RenderIntent /*intent*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+std::array<float, 16> FakeComposerClient::getDataspaceSaturationMatrix(
+ graphics::common::V1_1::Dataspace /*dataspace*/) {
+ return {};
+}
+
+// Composer 2.3
+V2_1::Error FakeComposerClient::getPerFrameMetadataKeys_2_3(
+ Display /*display*/, std::vector<V2_3::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setColorMode_2_3(Display /*display*/,
+ graphics::common::V1_2::ColorMode /*mode*/,
+ graphics::common::V1_1::RenderIntent /*intent*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getRenderIntents_2_3(
+ Display /*display*/, graphics::common::V1_2::ColorMode /*mode*/,
+ std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getColorModes_2_3(
+ Display /*display*/, hidl_vec<graphics::common::V1_2::ColorMode>* /*outModes*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getClientTargetSupport_2_3(
+ Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
+ graphics::common::V1_2::PixelFormat /*format*/,
+ graphics::common::V1_2::Dataspace /*dataspace*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getReadbackBufferAttributes_2_3(
+ Display /*display*/, graphics::common::V1_2::PixelFormat* /*outFormat*/,
+ graphics::common::V1_2::Dataspace* /*outDataspace*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getHdrCapabilities_2_3(
+ Display /*display*/, hidl_vec<graphics::common::V1_2::Hdr>* /*outTypes*/,
+ float* /*outMaxLuminance*/, float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerPerFrameMetadata_2_3(
+ Display /*display*/, Layer /*layer*/,
+ const std::vector<V2_3::IComposerClient::PerFrameMetadata>& /*metadata*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayIdentificationData(Display /*display*/,
+ uint8_t* /*outPort*/,
+ std::vector<uint8_t>* /*outData*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerColorTransform(Display /*display*/, Layer /*layer*/,
+ const float* /*matrix*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayedContentSamplingAttributes(
+ uint64_t /*display*/, graphics::common::V1_2::PixelFormat& /*format*/,
+ graphics::common::V1_2::Dataspace& /*dataspace*/,
+ hidl_bitfield<V2_3::IComposerClient::FormatColorComponent>& /*componentMask*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setDisplayedContentSamplingEnabled(
+ uint64_t /*display*/, V2_3::IComposerClient::DisplayedContentSampling /*enable*/,
+ hidl_bitfield<V2_3::IComposerClient::FormatColorComponent> /*componentMask*/,
+ uint64_t /*maxFrames*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayedContentSample(
+ uint64_t /*display*/, uint64_t /*maxFrames*/, uint64_t /*timestamp*/,
+ uint64_t& /*frameCount*/, hidl_vec<uint64_t>& /*sampleComponent0*/,
+ hidl_vec<uint64_t>& /*sampleComponent1*/, hidl_vec<uint64_t>& /*sampleComponent2*/,
+ hidl_vec<uint64_t>& /*sampleComponent3*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayCapabilities(
+ Display /*display*/,
+ std::vector<V2_3::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerPerFrameMetadataBlobs(
+ Display /*display*/, Layer /*layer*/,
+ std::vector<V2_3::IComposerClient::PerFrameMetadataBlob>& /*blobs*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayBrightnessSupport(Display /*display*/,
+ bool* /*outSupport*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setDisplayBrightness(Display /*display*/, float /*brightness*/) {
+ return V2_1::Error::UNSUPPORTED;
+}
+
+// Composer 2.4
+void FakeComposerClient::registerEventCallback_2_4(EventCallback_2_4* callback) {
+ ALOGV("registerEventCallback_2_4");
+ LOG_FATAL_IF(mEventCallback != nullptr, "already registered using registerEventCallback");
+
+ mEventCallback_2_4 = callback;
+ if (mEventCallback_2_4) {
+ mEventCallback_2_4->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+ }
+}
+
+void FakeComposerClient::unregisterEventCallback_2_4() {
+ ALOGV("unregisterEventCallback_2_4");
+ mEventCallback_2_4 = nullptr;
+}
+
+V2_4::Error FakeComposerClient::getDisplayCapabilities_2_4(
+ Display /*display*/,
+ std::vector<V2_4::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
+ return V2_4::Error::UNSUPPORTED;
+}
+
+V2_4::Error FakeComposerClient::getDisplayConnectionType(
+ Display /*display*/, V2_4::IComposerClient::DisplayConnectionType* /*outType*/) {
+ return V2_4::Error::UNSUPPORTED;
+}
+
+V2_4::Error FakeComposerClient::getDisplayAttribute_2_4(Display display, Config config,
+ IComposerClient::Attribute attribute,
+ int32_t* outValue) {
ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
static_cast<int>(config), static_cast<int>(attribute), outValue);
+ if (mMockHal) {
+ return mMockHal->getDisplayAttribute_2_4(display, config, attribute, outValue);
+ }
// TODO: SOOO much fun to be had with these alone
switch (attribute) {
@@ -276,233 +742,69 @@
return Error::NONE;
}
-Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) {
- ALOGV("getDisplayConfigs");
- // TODO assert display == 1, outConfigs != nullptr
+V2_4::Error FakeComposerClient::getDisplayVsyncPeriod(Display display,
+ V2_4::VsyncPeriodNanos* outVsyncPeriod) {
+ ALOGV("getDisplayVsyncPeriod");
+ if (mMockHal) {
+ return mMockHal->getDisplayVsyncPeriod(display, outVsyncPeriod);
+ }
- outConfigs->resize(1);
- (*outConfigs)[0] = 1;
-
- return Error::NONE;
+ return V2_4::Error::UNSUPPORTED;
}
-Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
- ALOGV("getDisplayName");
- return Error::NONE;
+V2_4::Error FakeComposerClient::setActiveConfigWithConstraints(
+ Display display, Config config,
+ const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* timeline) {
+ ALOGV("setActiveConfigWithConstraints");
+ if (mMockHal) {
+ return mMockHal->setActiveConfigWithConstraints(display, config,
+ vsyncPeriodChangeConstraints, timeline);
+ }
+ return V2_4::Error::UNSUPPORTED;
}
-Error FakeComposerClient::getDisplayType(Display /*display*/,
- IComposerClient::DisplayType* outType) {
- ALOGV("getDisplayType");
- // TODO: This setting nothing on the output had no effect on initial trials. Is first display
- // assumed to be physical?
- *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
- return Error::NONE;
+V2_4::Error FakeComposerClient::setAutoLowLatencyMode(Display, bool) {
+ ALOGV("setAutoLowLatencyMode");
+ return V2_4::Error::UNSUPPORTED;
}
-Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
- ALOGV("getDozeSupport");
- return Error::NONE;
+V2_4::Error FakeComposerClient::getSupportedContentTypes(
+ Display, std::vector<IComposerClient::ContentType>*) {
+ ALOGV("getSupportedContentTypes");
+ return V2_4::Error::UNSUPPORTED;
}
-Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/,
- float* /*outMaxLuminance*/,
- float* /*outMaxAverageLuminance*/,
- float* /*outMinLuminance*/) {
- ALOGV("getHdrCapabilities");
- return Error::NONE;
+V2_4::Error FakeComposerClient::setContentType(Display, IComposerClient::ContentType) {
+ ALOGV("setContentType");
+ return V2_4::Error::UNSUPPORTED;
}
-Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) {
- ALOGV("setActiveConfig");
- mCurrentConfig = config;
- return Error::NONE;
-}
-
-Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) {
- ALOGV("setColorMode");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) {
- ALOGV("setPowerMode");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) {
- mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
- ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
- int32_t /*hint*/) {
- ALOGV("setColorTransform");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
- int32_t /*acquireFence*/, int32_t /*dataspace*/,
- const std::vector<hwc_rect_t>& /*damage*/) {
- ALOGV("setClientTarget");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
- int32_t /*releaseFence*/) {
- ALOGV("setOutputBuffer");
- return Error::NONE;
-}
-
-Error FakeComposerClient::validateDisplay(
+V2_4::Error FakeComposerClient::validateDisplay_2_4(
Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
- std::vector<uint32_t>* /*outRequestMasks*/) {
- ALOGV("validateDisplay");
- // TODO: Assume touching nothing means All Korrekt!
- return Error::NONE;
+ std::vector<uint32_t>* /*outRequestMasks*/,
+ IComposerClient::ClientTargetProperty* /*outClientTargetProperty*/) {
+ return V2_4::Error::NONE;
}
-Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
- ALOGV("acceptDisplayChanges");
- // Didn't ask for changes because software is omnipotent.
- return Error::NONE;
+V2_4::Error FakeComposerClient::setLayerGenericMetadata(Display, Layer, const std::string&, bool,
+ const std::vector<uint8_t>&) {
+ ALOGV("setLayerGenericMetadata");
+ return V2_4::Error::UNSUPPORTED;
}
-bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
- return a->z <= b->z;
-}
-
-Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
- std::vector<Layer>* /*outLayers*/,
- std::vector<int32_t>* /*outReleaseFences*/) {
- ALOGV("presentDisplay");
- // TODO Leaving layers and their fences out for now. Doing so
- // means that we've already processed everything. Important to
- // test that the fences are respected, though. (How?)
-
- std::unique_ptr<Frame> newFrame(new Frame);
- for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
- const LayerImpl& layerImpl = *mLayers[layer];
-
- if (!layerImpl.mValid) continue;
-
- auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
- newFrame->rectangles.push_back(std::move(rect));
- }
- std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
- {
- Mutex::Autolock _l(mStateMutex);
- mFrames.push_back(std::move(newFrame));
- mFramesAvailable.broadcast();
- }
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
- int32_t /*x*/, int32_t /*y*/) {
- ALOGV("setLayerCursorPosition");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer,
- int32_t acquireFence) {
- ALOGV("setLayerBuffer");
- LayerImpl& l = getLayerImpl(layer);
- if (buffer != l.mRenderState.mBuffer) {
- l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
- }
- l.mRenderState.mBuffer = buffer;
- l.mRenderState.mAcquireFence = acquireFence;
-
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
- const std::vector<hwc_rect_t>& /*damage*/) {
- ALOGV("setLayerSurfaceDamage");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
- ALOGV("setLayerBlendMode");
- getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
- IComposerClient::Color color) {
- ALOGV("setLayerColor");
- getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
- getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
- getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
- getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
- int32_t /*type*/) {
- ALOGV("setLayerCompositionType");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
- int32_t /*dataspace*/) {
- ALOGV("setLayerDataspace");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
- const hwc_rect_t& frame) {
- ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
- frame.bottom);
- getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
- ALOGV("setLayerPlaneAlpha");
- getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
- buffer_handle_t /*stream*/) {
- ALOGV("setLayerSidebandStream");
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
- const hwc_frect_t& crop) {
- ALOGV("setLayerSourceCrop");
- getLayerImpl(layer).mRenderState.mSourceCrop = crop;
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) {
- ALOGV("setLayerTransform");
- getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
- const std::vector<hwc_rect_t>& visible) {
- ALOGV("setLayerVisibleRegion");
- getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
- return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
- ALOGV("setLayerZOrder");
- getLayerImpl(layer).mZ = z;
- return Error::NONE;
+V2_4::Error FakeComposerClient::getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>*) {
+ ALOGV("getLayerGenericMetadataKeys");
+ return V2_4::Error::UNSUPPORTED;
}
//////////////////////////////////////////////////////////////////
void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
- if (mEventCallback) {
+ if (mEventCallback || mEventCallback_2_4) {
uint64_t timestamp = vsyncTime;
ALOGV("Vsync");
if (timestamp == 0) {
@@ -512,8 +814,10 @@
}
if (mSurfaceComposer != nullptr) {
mSurfaceComposer->injectVSync(timestamp);
- } else {
+ } else if (mEventCallback) {
mEventCallback->onVsync(PRIMARY_DISPLAY, timestamp);
+ } else {
+ mEventCallback_2_4->onVsync_2_4(PRIMARY_DISPLAY, timestamp, 16'666'666);
}
}
}
@@ -617,3 +921,6 @@
// this might get more involving.
return static_cast<Layer>(index);
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index d115d79..600e765 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -16,22 +16,21 @@
#pragma once
-#define HWC2_USE_CPP11
-#define HWC2_INCLUDE_STRINGIFICATION
-#include <composer-hal/2.1/ComposerClient.h>
-#undef HWC2_USE_CPP11
-#undef HWC2_INCLUDE_STRINGIFICATION
-#include "RenderState.h"
-
-// Needed for display type/ID enums
-#include <hardware/hwcomposer_defs.h>
-
-#include <utils/Condition.h>
-
#include <chrono>
-using namespace android::hardware::graphics::composer::V2_1;
-using namespace android::hardware::graphics::composer::V2_1::hal;
+#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.4/ComposerClient.h>
+#include <utils/Condition.h>
+
+#include "MockComposerHal.h"
+#include "RenderState.h"
+
+using namespace android::hardware::graphics::common;
+using namespace android::hardware::graphics::composer;
+using namespace android::hardware::graphics::composer::V2_4;
+using namespace android::hardware::graphics::composer::V2_4::hal;
using namespace android::hardware;
using namespace std::chrono_literals;
@@ -46,7 +45,6 @@
} // namespace android
namespace sftest {
-
// NOTE: The ID's need to be exactly these. VR composer and parts of
// the SurfaceFlinger assume the display IDs to have these values
// despite the enum being documented as a display type.
@@ -59,6 +57,8 @@
FakeComposerClient();
virtual ~FakeComposerClient();
+ void setMockHal(MockComposerHal* mockHal) { mMockHal = mockHal; }
+
bool hasCapability(hwc2_capability_t capability) override;
std::string dumpDebugInfo() override;
@@ -66,59 +66,193 @@
void unregisterEventCallback() override;
uint32_t getMaxVirtualDisplayCount() override;
- Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
- Display* outDisplay) override;
- Error destroyVirtualDisplay(Display display) override;
- Error createLayer(Display display, Layer* outLayer) override;
- Error destroyLayer(Display display, Layer layer) override;
+ V2_1::Error createVirtualDisplay(uint32_t width, uint32_t height, V1_0::PixelFormat* format,
+ Display* outDisplay) override;
+ V2_1::Error destroyVirtualDisplay(Display display) override;
+ V2_1::Error createLayer(Display display, Layer* outLayer) override;
+ V2_1::Error destroyLayer(Display display, Layer layer) override;
- Error getActiveConfig(Display display, Config* outConfig) override;
- Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace) override;
- Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override;
- Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
- int32_t* outValue) override;
- Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
- Error getDisplayName(Display display, hidl_string* outName) override;
- Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
- Error getDozeSupport(Display display, bool* outSupport) override;
- Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance,
- float* outMaxAverageLuminance, float* outMinLuminance) override;
+ V2_1::Error getActiveConfig(Display display, Config* outConfig) override;
+ V2_1::Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+ V1_0::PixelFormat format,
+ V1_0::Dataspace dataspace) override;
+ V2_1::Error getColorModes(Display display, hidl_vec<V1_0::ColorMode>* outModes) override;
+ V2_1::Error getDisplayAttribute(Display display, Config config,
+ V2_1::IComposerClient::Attribute attribute,
+ int32_t* outValue) override;
+ V2_1::Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
+ V2_1::Error getDisplayName(Display display, hidl_string* outName) override;
+ V2_1::Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
+ V2_1::Error getDozeSupport(Display display, bool* outSupport) override;
+ V2_1::Error getHdrCapabilities(Display display, hidl_vec<V1_0::Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) override;
- Error setActiveConfig(Display display, Config config) override;
- Error setColorMode(Display display, ColorMode mode) override;
- Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
- Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
+ V2_1::Error setActiveConfig(Display display, Config config) override;
+ V2_1::Error setColorMode(Display display, V1_0::ColorMode mode) override;
+ V2_1::Error setPowerMode(Display display, V2_1::IComposerClient::PowerMode mode) override;
+ V2_1::Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
- Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
- Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
- int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
- Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override;
- Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) override;
- Error acceptDisplayChanges(Display display) override;
- Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) override;
+ V2_1::Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
+ V2_1::Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
+ int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
+ V2_1::Error setOutputBuffer(Display display, buffer_handle_t buffer,
+ int32_t releaseFence) override;
+ V2_1::Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask,
+ std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) override;
+ V2_1::Error acceptDisplayChanges(Display display) override;
+ V2_1::Error presentDisplay(Display display, int32_t* outPresentFence,
+ std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) override;
- Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
- Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
- int32_t acquireFence) override;
- Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) override;
- Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
- Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
- Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
- Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
- Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override;
- Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
- Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override;
- Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
- Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
- Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) override;
- Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+ V2_1::Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
+ V2_1::Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+ int32_t acquireFence) override;
+ V2_1::Error setLayerSurfaceDamage(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& damage) override;
+ V2_1::Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
+ V2_1::Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
+ V2_1::Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
+ V2_1::Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
+ V2_1::Error setLayerDisplayFrame(Display display, Layer layer,
+ const hwc_rect_t& frame) override;
+ V2_1::Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
+ V2_1::Error setLayerSidebandStream(Display display, Layer layer,
+ buffer_handle_t stream) override;
+ V2_1::Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
+ V2_1::Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
+ V2_1::Error setLayerVisibleRegion(Display display, Layer layer,
+ const std::vector<hwc_rect_t>& visible) override;
+ V2_1::Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+ // Composer 2.2
+ V2_1::Error getPerFrameMetadataKeys(
+ Display display,
+ std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* outKeys) override;
+ V2_1::Error setLayerPerFrameMetadata(
+ Display display, Layer layer,
+ const std::vector<V2_2::IComposerClient::PerFrameMetadata>& metadata) override;
+
+ V2_1::Error getReadbackBufferAttributes(
+ Display display, graphics::common::V1_1::PixelFormat* outFormat,
+ graphics::common::V1_1::Dataspace* outDataspace) override;
+ V2_1::Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+ android::base::unique_fd fenceFd) override;
+ V2_1::Error getReadbackBufferFence(Display display,
+ android::base::unique_fd* outFenceFd) override;
+ V2_1::Error createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+ graphics::common::V1_1::PixelFormat* format,
+ Display* outDisplay) override;
+ V2_1::Error getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
+ graphics::common::V1_1::PixelFormat format,
+ graphics::common::V1_1::Dataspace dataspace) override;
+ V2_1::Error setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) override;
+
+ V2_1::Error setLayerFloatColor(Display display, Layer layer,
+ V2_2::IComposerClient::FloatColor color) override;
+
+ V2_1::Error getColorModes_2_2(Display display,
+ hidl_vec<graphics::common::V1_1::ColorMode>* outModes) override;
+ V2_1::Error getRenderIntents(
+ Display display, graphics::common::V1_1::ColorMode mode,
+ std::vector<graphics::common::V1_1::RenderIntent>* outIntents) override;
+ V2_1::Error setColorMode_2_2(Display display, graphics::common::V1_1::ColorMode mode,
+ graphics::common::V1_1::RenderIntent intent) override;
+
+ std::array<float, 16> getDataspaceSaturationMatrix(
+ graphics::common::V1_1::Dataspace dataspace) override;
+
+ // Composer 2.3
+ V2_1::Error getPerFrameMetadataKeys_2_3(
+ Display display,
+ std::vector<V2_3::IComposerClient::PerFrameMetadataKey>* outKeys) override;
+
+ V2_1::Error setColorMode_2_3(Display display, graphics::common::V1_2::ColorMode mode,
+ graphics::common::V1_1::RenderIntent intent) override;
+
+ V2_1::Error getRenderIntents_2_3(
+ Display display, graphics::common::V1_2::ColorMode mode,
+ std::vector<graphics::common::V1_1::RenderIntent>* outIntents) override;
+
+ V2_1::Error getColorModes_2_3(Display display,
+ hidl_vec<graphics::common::V1_2::ColorMode>* outModes) override;
+
+ V2_1::Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
+ graphics::common::V1_2::PixelFormat format,
+ graphics::common::V1_2::Dataspace dataspace) override;
+ V2_1::Error getReadbackBufferAttributes_2_3(
+ Display display, graphics::common::V1_2::PixelFormat* outFormat,
+ graphics::common::V1_2::Dataspace* outDataspace) override;
+ V2_1::Error getHdrCapabilities_2_3(Display display,
+ hidl_vec<graphics::common::V1_2::Hdr>* outTypes,
+ float* outMaxLuminance, float* outMaxAverageLuminance,
+ float* outMinLuminance) override;
+ V2_1::Error setLayerPerFrameMetadata_2_3(
+ Display display, Layer layer,
+ const std::vector<V2_3::IComposerClient::PerFrameMetadata>& metadata) override;
+ V2_1::Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) override;
+ V2_1::Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override;
+ V2_1::Error getDisplayedContentSamplingAttributes(
+ uint64_t display, graphics::common::V1_2::PixelFormat& format,
+ graphics::common::V1_2::Dataspace& dataspace,
+ hidl_bitfield<V2_3::IComposerClient::FormatColorComponent>& componentMask) override;
+ V2_1::Error setDisplayedContentSamplingEnabled(
+ uint64_t display, V2_3::IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<V2_3::IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) override;
+ V2_1::Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+ uint64_t& frameCount,
+ hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) override;
+ V2_1::Error getDisplayCapabilities(
+ Display display,
+ std::vector<V2_3::IComposerClient::DisplayCapability>* outCapabilities) override;
+ V2_1::Error setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ std::vector<V2_3::IComposerClient::PerFrameMetadataBlob>& blobs) override;
+ V2_1::Error getDisplayBrightnessSupport(Display display, bool* outSupport) override;
+ V2_1::Error setDisplayBrightness(Display display, float brightness) override;
+
+ // Composer 2.4
+ void registerEventCallback_2_4(EventCallback_2_4* callback) override;
+
+ void unregisterEventCallback_2_4() override;
+
+ V2_4::Error getDisplayCapabilities_2_4(
+ Display display,
+ std::vector<V2_4::IComposerClient::DisplayCapability>* outCapabilities) override;
+ V2_4::Error getDisplayConnectionType(
+ Display display, V2_4::IComposerClient::DisplayConnectionType* outType) override;
+ V2_4::Error getDisplayAttribute_2_4(Display display, Config config,
+ IComposerClient::Attribute attribute,
+ int32_t* outValue) override;
+ V2_4::Error getDisplayVsyncPeriod(Display display,
+ V2_4::VsyncPeriodNanos* outVsyncPeriod) override;
+ V2_4::Error setActiveConfigWithConstraints(
+ Display display, Config config,
+ const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+ VsyncPeriodChangeTimeline* outTimeline) override;
+ V2_4::Error setAutoLowLatencyMode(Display display, bool on) override;
+ V2_4::Error getSupportedContentTypes(
+ Display display,
+ std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
+ V2_4::Error setContentType(Display display, IComposerClient::ContentType type) override;
+ V2_4::Error validateDisplay_2_4(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks,
+ IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
+ V2_4::Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+ bool mandatory, const std::vector<uint8_t>& value) override;
+ V2_4::Error getLayerGenericMetadataKeys(
+ std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
void setClient(ComposerClient* client);
@@ -150,6 +284,7 @@
LayerImpl& getLayerImpl(Layer handle);
EventCallback* mEventCallback;
+ EventCallback_2_4* mEventCallback_2_4;
Config mCurrentConfig;
bool mVsyncEnabled;
std::vector<std::unique_ptr<LayerImpl>> mLayers;
@@ -159,6 +294,8 @@
android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections
mutable android::Mutex mStateMutex;
mutable android::Condition mFramesAvailable;
+
+ MockComposerHal* mMockHal = nullptr;
};
} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
index f70cbdb..c656eed 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeHwcService"
@@ -22,35 +26,154 @@
#include "FakeComposerService.h"
using namespace android::hardware;
+using namespace android::hardware::graphics::composer;
namespace sftest {
-FakeComposerService::FakeComposerService(android::sp<ComposerClient>& client) : mClient(client) {}
+FakeComposerService_2_1::FakeComposerService_2_1(android::sp<ComposerClient>& client)
+ : mClient(client) {}
-FakeComposerService::~FakeComposerService() {
+FakeComposerService_2_1::~FakeComposerService_2_1() {
ALOGI("Maybe killing client %p", mClient.get());
// Rely on sp to kill the client.
}
-Return<void> FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) {
+Return<void> FakeComposerService_2_1::getCapabilities(getCapabilities_cb hidl_cb) {
ALOGI("FakeComposerService::getCapabilities");
hidl_cb(hidl_vec<Capability>());
return Void();
}
-Return<void> FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+Return<void> FakeComposerService_2_1::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
ALOGI("FakeComposerService::dumpDebugInfo");
hidl_cb(hidl_string());
return Void();
}
-Return<void> FakeComposerService::createClient(createClient_cb hidl_cb) {
+Return<void> FakeComposerService_2_1::createClient(createClient_cb hidl_cb) {
ALOGI("FakeComposerService::createClient %p", mClient.get());
if (!mClient->init()) {
LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
}
- hidl_cb(Error::NONE, mClient);
+ hidl_cb(V2_1::Error::NONE, mClient);
+ return Void();
+}
+
+FakeComposerService_2_2::FakeComposerService_2_2(android::sp<ComposerClient>& client)
+ : mClient(client) {}
+
+FakeComposerService_2_2::~FakeComposerService_2_2() {
+ ALOGI("Maybe killing client %p", mClient.get());
+ // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService_2_2::getCapabilities(getCapabilities_cb hidl_cb) {
+ ALOGI("FakeComposerService::getCapabilities");
+ hidl_cb(hidl_vec<Capability>());
+ return Void();
+}
+
+Return<void> FakeComposerService_2_2::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+ ALOGI("FakeComposerService::dumpDebugInfo");
+ hidl_cb(hidl_string());
+ return Void();
+}
+
+Return<void> FakeComposerService_2_2::createClient(createClient_cb hidl_cb) {
+ ALOGI("FakeComposerService::createClient %p", mClient.get());
+ if (!mClient->init()) {
+ LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+ }
+ hidl_cb(V2_1::Error::NONE, mClient);
+ return Void();
+}
+
+FakeComposerService_2_3::FakeComposerService_2_3(android::sp<ComposerClient>& client)
+ : mClient(client) {}
+
+FakeComposerService_2_3::~FakeComposerService_2_3() {
+ ALOGI("Maybe killing client %p", mClient.get());
+ // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService_2_3::getCapabilities(getCapabilities_cb hidl_cb) {
+ ALOGI("FakeComposerService::getCapabilities");
+ hidl_cb(hidl_vec<Capability>());
+ return Void();
+}
+
+Return<void> FakeComposerService_2_3::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+ ALOGI("FakeComposerService::dumpDebugInfo");
+ hidl_cb(hidl_string());
+ return Void();
+}
+
+Return<void> FakeComposerService_2_3::createClient(createClient_cb hidl_cb) {
+ LOG_ALWAYS_FATAL("createClient called on FakeComposerService_2_3");
+ if (!mClient->init()) {
+ LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+ }
+ hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
+ return Void();
+}
+
+Return<void> FakeComposerService_2_3::createClient_2_3(createClient_2_3_cb hidl_cb) {
+ ALOGI("FakeComposerService_2_3::createClient_2_3 %p", mClient.get());
+ if (!mClient->init()) {
+ LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+ }
+ hidl_cb(V2_1::Error::NONE, mClient);
+ return Void();
+}
+
+FakeComposerService_2_4::FakeComposerService_2_4(android::sp<ComposerClient>& client)
+ : mClient(client) {}
+
+FakeComposerService_2_4::~FakeComposerService_2_4() {
+ ALOGI("Maybe killing client %p", mClient.get());
+ // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService_2_4::getCapabilities(getCapabilities_cb hidl_cb) {
+ ALOGI("FakeComposerService::getCapabilities");
+ hidl_cb(hidl_vec<Capability>());
+ return Void();
+}
+
+Return<void> FakeComposerService_2_4::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+ ALOGI("FakeComposerService::dumpDebugInfo");
+ hidl_cb(hidl_string());
+ return Void();
+}
+
+Return<void> FakeComposerService_2_4::createClient(createClient_cb hidl_cb) {
+ LOG_ALWAYS_FATAL("createClient called on FakeComposerService_2_4");
+ if (!mClient->init()) {
+ LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+ }
+ hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
+ return Void();
+}
+
+Return<void> FakeComposerService_2_4::createClient_2_3(createClient_2_3_cb hidl_cb) {
+ LOG_ALWAYS_FATAL("createClient_2_3 called on FakeComposerService_2_4");
+ if (!mClient->init()) {
+ LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+ }
+ hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
+ return Void();
+}
+
+Return<void> FakeComposerService_2_4::createClient_2_4(createClient_2_4_cb hidl_cb) {
+ ALOGI("FakeComposerService_2_4::createClient_2_4 %p", mClient.get());
+ if (!mClient->init()) {
+ LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+ }
+ hidl_cb(V2_4::Error::NONE, mClient);
return Void();
}
} // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
index a3fb8a6..47f970f 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
@@ -16,18 +16,24 @@
#pragma once
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.4/ComposerClient.h>
-using namespace android::hardware::graphics::composer::V2_1;
-using namespace android::hardware::graphics::composer::V2_1::hal;
using android::hardware::Return;
+using ComposerClient = android::hardware::graphics::composer::V2_4::hal::ComposerClient;
+
namespace sftest {
-class FakeComposerService : public IComposer {
+using IComposer_2_1 = android::hardware::graphics::composer::V2_1::IComposer;
+
+class FakeComposerService_2_1 : public IComposer_2_1 {
public:
- explicit FakeComposerService(android::sp<ComposerClient>& client);
- virtual ~FakeComposerService();
+ explicit FakeComposerService_2_1(android::sp<ComposerClient>& client);
+ virtual ~FakeComposerService_2_1();
Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
@@ -37,4 +43,50 @@
android::sp<ComposerClient> mClient;
};
+using IComposer_2_2 = android::hardware::graphics::composer::V2_2::IComposer;
+class FakeComposerService_2_2 : public IComposer_2_2 {
+public:
+ explicit FakeComposerService_2_2(android::sp<ComposerClient>& client);
+ virtual ~FakeComposerService_2_2();
+
+ Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+ Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+ Return<void> createClient(createClient_cb hidl_cb) override;
+
+private:
+ android::sp<ComposerClient> mClient;
+};
+
+using IComposer_2_3 = android::hardware::graphics::composer::V2_3::IComposer;
+class FakeComposerService_2_3 : public IComposer_2_3 {
+public:
+ explicit FakeComposerService_2_3(android::sp<ComposerClient>& client);
+ virtual ~FakeComposerService_2_3();
+
+ Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+ Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+ Return<void> createClient(createClient_cb hidl_cb) override;
+ Return<void> createClient_2_3(createClient_2_3_cb hidl_cb) override;
+
+private:
+ android::sp<ComposerClient> mClient;
+};
+
+using IComposer_2_4 = android::hardware::graphics::composer::V2_4::IComposer;
+
+class FakeComposerService_2_4 : public IComposer_2_4 {
+public:
+ explicit FakeComposerService_2_4(android::sp<ComposerClient>& client);
+ virtual ~FakeComposerService_2_4();
+
+ Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+ Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+ Return<void> createClient(createClient_cb hidl_cb) override;
+ Return<void> createClient_2_3(createClient_2_3_cb hidl_cb) override;
+ Return<void> createClient_2_4(createClient_2_4_cb hidl_cb) override;
+
+private:
+ android::sp<ComposerClient> mClient;
+};
+
} // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 51956ec..1cea25a 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeHwcUtil"
@@ -25,8 +29,8 @@
#include "SurfaceFlinger.h" // Get the name of the service...
#include <binder/IServiceManager.h>
-
#include <cutils/properties.h>
+#include <hidl/ServiceManagement.h>
#include <iomanip>
#include <thread>
@@ -167,7 +171,9 @@
}
// TODO: Try registering the mock as the default service instead.
property_set("debug.sf.hwc_service_name", "mock");
- // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files.
+
+ // This allows tests/SF to register/load a HIDL service not listed in manifest files.
+ android::hardware::details::setTrebleTestingOverride(true);
property_set("debug.sf.treble_testing_override", "true");
}
@@ -177,7 +183,11 @@
// Wait for mock call signaling teardown?
property_set("debug.sf.nobootanimation", "0");
property_set("debug.sf.hwc_service_name", "default");
+ system("setenforce 1");
ALOGI("Test env tear down - done");
}
} // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
index 7d20d3c..383a111 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -19,11 +19,7 @@
#include "FakeComposerClient.h"
#include <gui/SurfaceComposerClient.h>
-
-#include <hardware/hwcomposer_defs.h>
-
#include <log/log.h>
-
#include <gtest/gtest.h>
// clang-format off
@@ -108,9 +104,9 @@
LOG_ALWAYS_FATAL_IF(android::NO_ERROR != apply());
// Make sure that exactly one frame has been rendered.
mComposer.waitUntilFrame(frameCount + 1);
- LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
- "Unexpected frame advance. Delta: %d",
- mComposer.getFrameCount() - frameCount);
+ // LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
+ // "Unexpected frame advance. Delta: %d",
+ // mComposer.getFrameCount() - frameCount);
}
FakeComposerClient& mComposer;
diff --git a/services/surfaceflinger/tests/fakehwc/MockComposerHal.h b/services/surfaceflinger/tests/fakehwc/MockComposerHal.h
new file mode 100644
index 0000000..5dc3778
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/MockComposerHal.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 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 <composer-hal/2.4/ComposerClient.h>
+
+#include <gmock/gmock.h>
+
+using namespace android::hardware::graphics::common;
+using namespace android::hardware::graphics::composer;
+using namespace android::hardware::graphics::composer::V2_4;
+using namespace android::hardware::graphics::composer::V2_4::hal;
+using namespace android::hardware;
+using namespace std::chrono_literals;
+
+namespace sftest {
+
+// Mock class for ComposerHal. Implements only the functions used in the test.
+class MockComposerHal {
+public:
+ MOCK_METHOD2(getActiveConfig, V2_1::Error(Display, Config*));
+ MOCK_METHOD4(getDisplayAttribute_2_4,
+ V2_4::Error(Display, Config, V2_4::IComposerClient::Attribute, int32_t*));
+ MOCK_METHOD2(getDisplayConfigs, V2_1::Error(Display, hidl_vec<Config>*));
+ MOCK_METHOD2(setActiveConfig, V2_1::Error(Display, Config));
+ MOCK_METHOD2(getDisplayVsyncPeriod, V2_4::Error(Display, V2_4::VsyncPeriodNanos*));
+ MOCK_METHOD4(setActiveConfigWithConstraints,
+ V2_4::Error(Display, Config,
+ const V2_4::IComposerClient::VsyncPeriodChangeConstraints&,
+ VsyncPeriodChangeTimeline*));
+};
+
+} // namespace sftest
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h
index 0059289..40193f2 100644
--- a/services/surfaceflinger/tests/fakehwc/RenderState.h
+++ b/services/surfaceflinger/tests/fakehwc/RenderState.h
@@ -16,8 +16,6 @@
#pragma once
-#include <hardware/hwcomposer2.h>
-
#include <vector>
namespace sftest {
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index a892a2a..a03fd89 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
// #define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeHwcTest"
@@ -21,6 +25,7 @@
#include "FakeComposerClient.h"
#include "FakeComposerService.h"
#include "FakeComposerUtils.h"
+#include "MockComposerHal.h"
#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
@@ -36,13 +41,14 @@
#include <hwbinder/ProcessState.h>
#include <log/log.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <utils/Looper.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <limits>
+#include <thread>
using namespace std::chrono_literals;
@@ -55,12 +61,14 @@
// Mock test helpers
using ::testing::_;
+using ::testing::AtLeast;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SetArgPointee;
using Transaction = SurfaceComposerClient::Transaction;
+using Attribute = V2_4::IComposerClient::Attribute;
///////////////////////////////////////////////
@@ -121,319 +129,1268 @@
static_cast<int>(bottom));
}
-////////////////////////////////////////////////
-
+///////////////////////////////////////////////
+template <typename FakeComposerService>
class DisplayTest : public ::testing::Test {
-public:
- class MockComposerClient : public FakeComposerClient {
- public:
- MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType));
- MOCK_METHOD4(getDisplayAttribute,
- Error(Display display, Config config, IComposerClient::Attribute attribute,
- int32_t* outValue));
-
- // Re-routing to basic fake implementation
- Error getDisplayAttributeFake(Display display, Config config,
- IComposerClient::Attribute attribute, int32_t* outValue) {
- return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue);
- }
+protected:
+ struct TestConfig {
+ int32_t id;
+ int32_t w;
+ int32_t h;
+ int32_t vsyncPeriod;
+ int32_t group;
};
-protected:
- static int processDisplayEvents(int fd, int events, void* data);
+ static int processDisplayEvents(int /*fd*/, int /*events*/, void* data) {
+ auto self = static_cast<DisplayTest*>(data);
- void SetUp() override;
- void TearDown() override;
+ ssize_t n;
+ DisplayEventReceiver::Event buffer[1];
- void waitForDisplayTransaction();
- bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected);
-
- sp<IComposer> mFakeService;
- sp<SurfaceComposerClient> mComposerClient;
-
- MockComposerClient* mMockComposer;
-
- std::unique_ptr<DisplayEventReceiver> mReceiver;
- sp<Looper> mLooper;;
- std::deque<DisplayEventReceiver::Event> mReceivedDisplayEvents;
-};
-
-void DisplayTest::SetUp() {
- // TODO: The mMockComposer should be a unique_ptr, but it needs to
- // outlive the test class. Currently ComposerClient only dies
- // when the service is replaced. The Mock deletes itself when
- // removeClient is called on it, which is ugly. This can be
- // changed if HIDL ServiceManager allows removing services or
- // ComposerClient starts taking the ownership of the contained
- // implementation class. Moving the fake class to the HWC2
- // interface instead of the current Composer interface might also
- // change the situation.
- mMockComposer = new MockComposerClient;
- sp<ComposerClient> client = new ComposerClient(mMockComposer);
- mFakeService = new FakeComposerService(client);
- (void)mFakeService->registerAsService("mock");
-
- android::hardware::ProcessState::self()->startThreadPool();
- android::ProcessState::self()->startThreadPool();
-
- EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
- .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
- Return(Error::NONE)));
- // Primary display will be queried twice for all 5 attributes. One
- // set of queries comes from the SurfaceFlinger proper an the
- // other set from the VR composer.
- // TODO: Is VR composer always present? Change to atLeast(5)?
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
- .Times(2 * 5)
- .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
-
- startSurfaceFlinger();
-
- // Fake composer wants to enable VSync injection
- mMockComposer->onSurfaceFlingerStart();
-
- mComposerClient = new SurfaceComposerClient;
- ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
- mReceiver.reset(new DisplayEventReceiver());
- mLooper = new Looper(false);
- mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
-}
-
-void DisplayTest::TearDown() {
- mLooper = nullptr;
- mReceiver = nullptr;
-
- mComposerClient->dispose();
- mComposerClient = nullptr;
-
- // Fake composer needs to release SurfaceComposerClient before the stop.
- mMockComposer->onSurfaceFlingerStop();
- stopSurfaceFlinger();
-
- mFakeService = nullptr;
- // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
- // management.
- mMockComposer = nullptr;
-}
-
-
-int DisplayTest::processDisplayEvents(int /*fd*/, int /*events*/, void* data) {
- auto self = static_cast<DisplayTest*>(data);
-
- ssize_t n;
- DisplayEventReceiver::Event buffer[1];
-
- while ((n = self->mReceiver->getEvents(buffer, 1)) > 0) {
- for (int i=0 ; i<n ; i++) {
- self->mReceivedDisplayEvents.push_back(buffer[i]);
+ while ((n = self->mReceiver->getEvents(buffer, 1)) > 0) {
+ for (int i = 0; i < n; i++) {
+ self->mReceivedDisplayEvents.push_back(buffer[i]);
+ }
}
+ ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
+ return 1;
}
- ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
- return 1;
-}
-void DisplayTest::waitForDisplayTransaction() {
- // Both a refresh and a vsync event are needed to apply pending display
- // transactions.
- mMockComposer->refreshDisplay(EXTERNAL_DISPLAY);
- mMockComposer->runVSyncAndWait();
+ Error getDisplayAttributeNoMock(Display display, Config config,
+ V2_4::IComposerClient::Attribute attribute, int32_t* outValue) {
+ mFakeComposerClient->setMockHal(nullptr);
+ auto ret =
+ mFakeComposerClient->getDisplayAttribute_2_4(display, config, attribute, outValue);
+ mFakeComposerClient->setMockHal(mMockComposer.get());
+ return ret;
+ }
- // Extra vsync and wait to avoid a 10% flake due to a race.
- mMockComposer->runVSyncAndWait();
-}
+ void setExpectationsForConfigs(Display display, std::vector<TestConfig> testConfigs,
+ Config activeConfig, V2_4::VsyncPeriodNanos defaultVsyncPeriod) {
+ std::vector<Config> configIds;
+ for (int i = 0; i < testConfigs.size(); i++) {
+ configIds.push_back(testConfigs[i].id);
-bool DisplayTest::waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
- int waitCount = 20;
- while (waitCount--) {
- while (!mReceivedDisplayEvents.empty()) {
- auto event = mReceivedDisplayEvents.front();
- mReceivedDisplayEvents.pop_front();
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].w), Return(Error::NONE)));
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].h), Return(Error::NONE)));
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::VSYNC_PERIOD,
+ _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].vsyncPeriod),
+ Return(Error::NONE)));
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::CONFIG_GROUP,
+ _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<3>(testConfigs[i].group), Return(Error::NONE)));
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::DPI_X, _))
+ .WillRepeatedly(Return(Error::UNSUPPORTED));
+ EXPECT_CALL(*mMockComposer,
+ getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::DPI_Y, _))
+ .WillRepeatedly(Return(Error::UNSUPPORTED));
+ }
- ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
- "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
- ", connected %d\t",
- event.header.displayId, event.hotplug.connected);
+ EXPECT_CALL(*mMockComposer, getDisplayConfigs(display, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(hidl_vec<Config>(configIds)),
+ Return(V2_1::Error::NONE)));
- if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
- event.header.displayId == displayId && event.hotplug.connected == connected) {
- return true;
+ EXPECT_CALL(*mMockComposer, getActiveConfig(display, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(activeConfig), Return(V2_1::Error::NONE)));
+
+ EXPECT_CALL(*mMockComposer, getDisplayVsyncPeriod(display, _))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<1>(defaultVsyncPeriod), Return(V2_4::Error::NONE)));
+ }
+
+ void SetUp() override {
+ mMockComposer = std::make_unique<MockComposerHal>();
+ mFakeComposerClient = new FakeComposerClient();
+ mFakeComposerClient->setMockHal(mMockComposer.get());
+
+ sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(mFakeComposerClient);
+ mFakeService = new FakeComposerService(client);
+ ASSERT_EQ(android::OK, mFakeService->registerAsService("mock"));
+
+ android::hardware::ProcessState::self()->startThreadPool();
+ android::ProcessState::self()->startThreadPool();
+
+ setExpectationsForConfigs(PRIMARY_DISPLAY,
+ {{
+ .id = 1,
+ .w = 1920,
+ .h = 1024,
+ .vsyncPeriod = 16'666'666,
+ .group = 0,
+ }},
+ 1, 16'666'666);
+
+ startSurfaceFlinger();
+
+ // Fake composer wants to enable VSync injection
+ mFakeComposerClient->onSurfaceFlingerStart();
+
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
+ ISurfaceComposer::eConfigChangedDispatch));
+ mLooper = new Looper(false);
+ mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
+ }
+
+ void TearDown() override {
+ mLooper = nullptr;
+ mReceiver = nullptr;
+
+ mComposerClient->dispose();
+ mComposerClient = nullptr;
+
+ // Fake composer needs to release SurfaceComposerClient before the stop.
+ mFakeComposerClient->onSurfaceFlingerStop();
+ stopSurfaceFlinger();
+
+ mFakeComposerClient->setMockHal(nullptr);
+
+ mFakeService = nullptr;
+ // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
+ // management.
+ mMockComposer = nullptr;
+ }
+
+ void waitForDisplayTransaction() {
+ // Both a refresh and a vsync event are needed to apply pending display
+ // transactions.
+ mFakeComposerClient->refreshDisplay(EXTERNAL_DISPLAY);
+ mFakeComposerClient->runVSyncAndWait();
+
+ // Extra vsync and wait to avoid a 10% flake due to a race.
+ mFakeComposerClient->runVSyncAndWait();
+ }
+
+ bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
+ int waitCount = 20;
+ while (waitCount--) {
+ while (!mReceivedDisplayEvents.empty()) {
+ auto event = mReceivedDisplayEvents.front();
+ mReceivedDisplayEvents.pop_front();
+
+ ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
+ "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", connected %d\t",
+ event.header.displayId, event.hotplug.connected);
+
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
+ event.header.displayId == displayId && event.hotplug.connected == connected) {
+ return true;
+ }
+ }
+
+ mLooper->pollOnce(1);
+ }
+ return false;
+ }
+
+ bool waitForConfigChangedEvent(PhysicalDisplayId displayId, int32_t configId) {
+ int waitCount = 20;
+ while (waitCount--) {
+ while (!mReceivedDisplayEvents.empty()) {
+ auto event = mReceivedDisplayEvents.front();
+ mReceivedDisplayEvents.pop_front();
+
+ ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED,
+ "event config: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", configId %d\t",
+ event.header.displayId, event.config.configId);
+
+ if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
+ event.header.displayId == displayId && event.config.configId == configId) {
+ return true;
+ }
+ }
+
+ mLooper->pollOnce(1);
+ }
+ return false;
+ }
+
+ void Test_HotplugOneConfig() {
+ ALOGD("DisplayTest::Test_Hotplug_oneConfig");
+
+ setExpectationsForConfigs(EXTERNAL_DISPLAY,
+ {{.id = 1,
+ .w = 200,
+ .h = 400,
+ .vsyncPeriod = 16'666'666,
+ .group = 0}},
+ 1, 16'666'666);
+
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::CONNECTED);
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
+
+ {
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
+
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
+ EXPECT_EQ(ui::Size(200, 400), resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
}
}
- mLooper->pollOnce(1);
- }
-
- return false;
-}
-
-TEST_F(DisplayTest, Hotplug) {
- ALOGD("DisplayTest::Hotplug");
-
- EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
- .Times(2)
- .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
- Return(Error::NONE)));
- // The attribute queries will get done twice. This is for defaults
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
- .Times(2 * 3)
- .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
- // ... and then special handling for dimensions. Specifying these
- // rules later means that gmock will try them first, i.e.,
- // ordering of width/height vs. the default implementation for
- // other queries is significant.
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
- .Times(2)
- .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
-
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
- .Times(2)
- .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
-
- mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
-
- waitForDisplayTransaction();
-
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
- {
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
- ASSERT_FALSE(display == nullptr);
-
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- ASSERT_EQ(400u, info.w);
- ASSERT_EQ(200u, info.h);
-
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(surfaceControl != nullptr);
- ASSERT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::DISCONNECTED);
+ waitForDisplayTransaction();
+ mFakeComposerClient->clearFrames();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
{
- TransactionScope ts(*mMockComposer);
- ts.setDisplayLayerStack(display, 0);
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ EXPECT_TRUE(display == nullptr);
- ts.setLayer(surfaceControl, INT32_MAX - 2)
- .show(surfaceControl);
+ DisplayConfig config;
+ EXPECT_NE(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
}
}
- mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+ void Test_HotplugTwoSeparateConfigs() {
+ ALOGD("DisplayTest::Test_HotplugTwoSeparateConfigs");
- mMockComposer->clearFrames();
+ setExpectationsForConfigs(EXTERNAL_DISPLAY,
+ {{.id = 1,
+ .w = 200,
+ .h = 400,
+ .vsyncPeriod = 16'666'666,
+ .group = 0},
+ {.id = 2,
+ .w = 800,
+ .h = 1600,
+ .vsyncPeriod = 11'111'111,
+ .group = 1}},
+ 1, 16'666'666);
- mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::CONNECTED);
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
- waitForDisplayTransaction();
-
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
- EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
- {
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
- ASSERT_FALSE(display == nullptr);
+ EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- ASSERT_EQ(400u, info.w);
- ASSERT_EQ(200u, info.h);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(200, 400), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
- auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(surfaceControl != nullptr);
- ASSERT_TRUE(surfaceControl->isValid());
- fillSurfaceRGBA8(surfaceControl, BLUE);
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ Vector<DisplayConfig> configs;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+ EXPECT_EQ(configs.size(), 2);
+
+ // change active config
+
+ if (mIs2_4Client) {
+ EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 2, _, _))
+ .WillOnce(Return(V2_4::Error::NONE));
+ } else {
+ EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 2))
+ .WillOnce(Return(V2_1::Error::NONE));
+ }
+
+ for (int i = 0; i < configs.size(); i++) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 800) {
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate));
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+ break;
+ }
+ }
+
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::DISCONNECTED);
+ waitForDisplayTransaction();
+ mFakeComposerClient->clearFrames();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+ }
+
+ void Test_HotplugTwoConfigsSameGroup() {
+ ALOGD("DisplayTest::Test_HotplugTwoConfigsSameGroup");
+
+ setExpectationsForConfigs(EXTERNAL_DISPLAY,
+ {{.id = 2,
+ .w = 800,
+ .h = 1600,
+ .vsyncPeriod = 16'666'666,
+ .group = 31},
+ {.id = 3,
+ .w = 800,
+ .h = 1600,
+ .vsyncPeriod = 11'111'111,
+ .group = 31}},
+ 2, 16'666'666);
+
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::CONNECTED);
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
+
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
+
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ Vector<DisplayConfig> configs;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+ EXPECT_EQ(configs.size(), 2);
+
+ // change active config
+ if (mIs2_4Client) {
+ EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
+ .WillOnce(Return(V2_4::Error::NONE));
+ } else {
+ EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 3))
+ .WillOnce(Return(V2_1::Error::NONE));
+ }
+
+ for (int i = 0; i < configs.size(); i++) {
+ const auto& config = configs[i];
+ if (config.refreshRate == 1e9f / 11'111'111) {
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate));
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+ break;
+ }
+ }
+
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::DISCONNECTED);
+ waitForDisplayTransaction();
+ mFakeComposerClient->clearFrames();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+ }
+
+ void Test_HotplugThreeConfigsMixedGroups() {
+ ALOGD("DisplayTest::Test_HotplugThreeConfigsMixedGroups");
+
+ setExpectationsForConfigs(EXTERNAL_DISPLAY,
+ {{.id = 2,
+ .w = 800,
+ .h = 1600,
+ .vsyncPeriod = 16'666'666,
+ .group = 0},
+ {.id = 3,
+ .w = 800,
+ .h = 1600,
+ .vsyncPeriod = 11'111'111,
+ .group = 0},
+ {.id = 4,
+ .w = 1600,
+ .h = 3200,
+ .vsyncPeriod = 8'333'333,
+ .group = 1},
+ {.id = 5,
+ .w = 1600,
+ .h = 3200,
+ .vsyncPeriod = 11'111'111,
+ .group = 1}},
+ 2, 16'666'666);
+
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::CONNECTED);
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
+
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
+
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ Vector<DisplayConfig> configs;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+ EXPECT_EQ(configs.size(), 4);
+
+ // change active config to 800x1600@90Hz
+ if (mIs2_4Client) {
+ EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
+ .WillOnce(Return(V2_4::Error::NONE));
+ } else {
+ EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 3))
+ .WillOnce(Return(V2_1::Error::NONE));
+ }
+
+ for (int i = 0; i < configs.size(); i++) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::
+ setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate,
+ configs[i].refreshRate));
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+ break;
+ }
+ }
+
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ // change active config to 1600x3200@120Hz
+ if (mIs2_4Client) {
+ EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 4, _, _))
+ .WillOnce(Return(V2_4::Error::NONE));
+ } else {
+ EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 4))
+ .WillOnce(Return(V2_1::Error::NONE));
+ }
+
+ for (int i = 0; i < configs.size(); i++) {
+ const auto& config = configs[i];
+ if (config.refreshRate == 1e9f / 8'333'333) {
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate));
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+ break;
+ }
+ }
+
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+ EXPECT_EQ(1e9f / 8'333'333, config.refreshRate);
+
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ // change active config to 1600x3200@90Hz
+ if (mIs2_4Client) {
+ EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 5, _, _))
+ .WillOnce(Return(V2_4::Error::NONE));
+ } else {
+ EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 5))
+ .WillOnce(Return(V2_1::Error::NONE));
+ }
+
+ for (int i = 0; i < configs.size(); i++) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
+ EXPECT_EQ(NO_ERROR,
+ SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate,
+ config.refreshRate));
+ waitForDisplayTransaction();
+ EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+ break;
+ }
+ }
+
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+ mFakeComposerClient->clearFrames();
+ {
+ const ui::Size& resolution = config.resolution;
+ auto surfaceControl =
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
+ EXPECT_TRUE(surfaceControl != nullptr);
+ EXPECT_TRUE(surfaceControl->isValid());
+ fillSurfaceRGBA8(surfaceControl, BLUE);
+
+ {
+ TransactionScope ts(*mFakeComposerClient);
+ ts.setDisplayLayerStack(display, 0);
+
+ ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+ }
+ }
+
+ mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+ V2_1::IComposerCallback::Connection::DISCONNECTED);
+ waitForDisplayTransaction();
+ mFakeComposerClient->clearFrames();
+ EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+ }
+
+ void Test_HotplugPrimaryDisplay() {
+ ALOGD("DisplayTest::HotplugPrimaryDisplay");
+
+ mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
+ V2_1::IComposerCallback::Connection::DISCONNECTED);
+
+ waitForDisplayTransaction();
+
+ EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
+ {
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ EXPECT_TRUE(display == nullptr);
+
+ DisplayConfig config;
+ auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
+ EXPECT_NE(NO_ERROR, result);
+ }
+
+ mFakeComposerClient->clearFrames();
+
+ setExpectationsForConfigs(PRIMARY_DISPLAY,
+ {{.id = 1,
+ .w = 400,
+ .h = 200,
+ .vsyncPeriod = 16'666'666,
+ .group = 0}},
+ 1, 16'666'666);
+
+ mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
+ V2_1::IComposerCallback::Connection::CONNECTED);
+
+ waitForDisplayTransaction();
+
+ EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
{
- TransactionScope ts(*mMockComposer);
- ts.setDisplayLayerStack(display, 0);
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ EXPECT_FALSE(display == nullptr);
- ts.setLayer(surfaceControl, INT32_MAX - 2)
- .show(surfaceControl);
+ DisplayConfig config;
+ auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
+ EXPECT_EQ(NO_ERROR, result);
+ ASSERT_EQ(ui::Size(400, 200), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
}
}
- mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+
+ sp<V2_1::IComposer> mFakeService;
+ sp<SurfaceComposerClient> mComposerClient;
+
+ std::unique_ptr<MockComposerHal> mMockComposer;
+ FakeComposerClient* mFakeComposerClient;
+
+ std::unique_ptr<DisplayEventReceiver> mReceiver;
+ sp<Looper> mLooper;
+ std::deque<DisplayEventReceiver::Event> mReceivedDisplayEvents;
+
+ static constexpr bool mIs2_4Client =
+ std::is_same<FakeComposerService, FakeComposerService_2_4>::value;
+};
+
+using DisplayTest_2_1 = DisplayTest<FakeComposerService_2_1>;
+
+TEST_F(DisplayTest_2_1, HotplugOneConfig) {
+ Test_HotplugOneConfig();
}
-TEST_F(DisplayTest, HotplugPrimaryDisplay) {
- ALOGD("DisplayTest::HotplugPrimaryDisplay");
+TEST_F(DisplayTest_2_1, HotplugTwoSeparateConfigs) {
+ Test_HotplugTwoSeparateConfigs();
+}
- mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+TEST_F(DisplayTest_2_1, HotplugTwoConfigsSameGroup) {
+ Test_HotplugTwoConfigsSameGroup();
+}
- waitForDisplayTransaction();
+TEST_F(DisplayTest_2_1, HotplugThreeConfigsMixedGroups) {
+ Test_HotplugThreeConfigsMixedGroups();
+}
- EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
+TEST_F(DisplayTest_2_1, HotplugPrimaryOneConfig) {
+ Test_HotplugPrimaryDisplay();
+}
- {
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
- EXPECT_FALSE(display == nullptr);
+using DisplayTest_2_2 = DisplayTest<FakeComposerService_2_2>;
- DisplayInfo info;
- auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
- EXPECT_NE(NO_ERROR, result);
- }
+TEST_F(DisplayTest_2_2, HotplugOneConfig) {
+ Test_HotplugOneConfig();
+}
- mMockComposer->clearFrames();
+TEST_F(DisplayTest_2_2, HotplugTwoSeparateConfigs) {
+ Test_HotplugTwoSeparateConfigs();
+}
- EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
- .Times(2)
- .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
- Return(Error::NONE)));
- // The attribute queries will get done twice. This is for defaults
- EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
- .Times(2 * 3)
- .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
- // ... and then special handling for dimensions. Specifying these
- // rules later means that gmock will try them first, i.e.,
- // ordering of width/height vs. the default implementation for
- // other queries is significant.
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
- .Times(2)
- .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
+TEST_F(DisplayTest_2_2, HotplugTwoConfigsSameGroup) {
+ Test_HotplugTwoConfigsSameGroup();
+}
- EXPECT_CALL(*mMockComposer,
- getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
- .Times(2)
- .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
+TEST_F(DisplayTest_2_2, HotplugThreeConfigsMixedGroups) {
+ Test_HotplugThreeConfigsMixedGroups();
+}
- mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+TEST_F(DisplayTest_2_2, HotplugPrimaryOneConfig) {
+ Test_HotplugPrimaryDisplay();
+}
- waitForDisplayTransaction();
+using DisplayTest_2_3 = DisplayTest<FakeComposerService_2_3>;
- EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
+TEST_F(DisplayTest_2_3, HotplugOneConfig) {
+ Test_HotplugOneConfig();
+}
- {
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
- EXPECT_FALSE(display == nullptr);
+TEST_F(DisplayTest_2_3, HotplugTwoSeparateConfigs) {
+ Test_HotplugTwoSeparateConfigs();
+}
- DisplayInfo info;
- auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
- EXPECT_EQ(NO_ERROR, result);
- ASSERT_EQ(400u, info.w);
- ASSERT_EQ(200u, info.h);
- }
+TEST_F(DisplayTest_2_3, HotplugTwoConfigsSameGroup) {
+ Test_HotplugTwoConfigsSameGroup();
+}
+
+TEST_F(DisplayTest_2_3, HotplugThreeConfigsMixedGroups) {
+ Test_HotplugThreeConfigsMixedGroups();
+}
+
+TEST_F(DisplayTest_2_3, HotplugPrimaryOneConfig) {
+ Test_HotplugPrimaryDisplay();
+}
+
+using DisplayTest_2_4 = DisplayTest<FakeComposerService_2_4>;
+
+TEST_F(DisplayTest_2_4, HotplugOneConfig) {
+ Test_HotplugOneConfig();
+}
+
+TEST_F(DisplayTest_2_4, HotplugTwoSeparateConfigs) {
+ Test_HotplugTwoSeparateConfigs();
+}
+
+TEST_F(DisplayTest_2_4, HotplugTwoConfigsSameGroup) {
+ Test_HotplugTwoConfigsSameGroup();
+}
+
+TEST_F(DisplayTest_2_4, HotplugThreeConfigsMixedGroups) {
+ Test_HotplugThreeConfigsMixedGroups();
+}
+
+TEST_F(DisplayTest_2_4, HotplugPrimaryOneConfig) {
+ Test_HotplugPrimaryDisplay();
}
////////////////////////////////////////////////
+template <typename FakeComposerService>
class TransactionTest : public ::testing::Test {
protected:
// Layer array indexing constants.
constexpr static int BG_LAYER = 0;
constexpr static int FG_LAYER = 1;
- static void SetUpTestCase();
- static void TearDownTestCase();
+ static void SetUpTestCase() {
+ // TODO: See TODO comment at DisplayTest::SetUp for background on
+ // the lifetime of the FakeComposerClient.
+ sFakeComposer = new FakeComposerClient;
+ sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(sFakeComposer);
+ sp<V2_1::IComposer> fakeService = new FakeComposerService(client);
+ (void)fakeService->registerAsService("mock");
- void SetUp() override;
- void TearDown() override;
+ android::hardware::ProcessState::self()->startThreadPool();
+ android::ProcessState::self()->startThreadPool();
+
+ startSurfaceFlinger();
+
+ // Fake composer wants to enable VSync injection
+ sFakeComposer->onSurfaceFlingerStart();
+ }
+
+ static void TearDownTestCase() {
+ // Fake composer needs to release SurfaceComposerClient before the stop.
+ sFakeComposer->onSurfaceFlingerStop();
+ stopSurfaceFlinger();
+ // TODO: This is deleted when the ComposerClient calls
+ // removeClient. Devise better lifetime control.
+ sFakeComposer = nullptr;
+ }
+
+ void SetUp() override {
+ ALOGI("TransactionTest::SetUp");
+ mComposerClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+ ALOGI("TransactionTest::SetUp - display");
+ const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+ ASSERT_FALSE(display == nullptr);
+
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+
+ const ui::Size& resolution = config.resolution;
+ mDisplayWidth = resolution.getWidth();
+ mDisplayHeight = resolution.getHeight();
+
+ // Background surface
+ mBGSurfaceControl =
+ mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
+ mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+ fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
+
+ // Foreground surface
+ mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mFGSurfaceControl != nullptr);
+ ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+ fillSurfaceRGBA8(mFGSurfaceControl, RED);
+
+ Transaction t;
+ t.setDisplayLayerStack(display, 0);
+
+ t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
+ t.show(mBGSurfaceControl);
+
+ t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ t.show(mFGSurfaceControl);
+
+ // Synchronous transaction will stop this thread, so we set up a
+ // delayed, off-thread vsync request before closing the
+ // transaction. In the test code this is usually done with
+ // TransactionScope. Leaving here in the 'vanilla' form for
+ // reference.
+ ASSERT_EQ(0, sFakeComposer->getFrameCount());
+ sFakeComposer->runVSyncAfter(1ms);
+ t.apply();
+ sFakeComposer->waitUntilFrame(1);
+
+ // Reference data. This is what the HWC should see.
+ static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
+ mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
+ mBaseFrame[BG_LAYER].mSwapCount = 1;
+ mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+ mBaseFrame[FG_LAYER].mSwapCount = 1;
+
+ auto frame = sFakeComposer->getFrameRects(0);
+ ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
+ }
+
+ void TearDown() override {
+ ALOGD("TransactionTest::TearDown");
+
+ mComposerClient->dispose();
+ mBGSurfaceControl = 0;
+ mFGSurfaceControl = 0;
+ mComposerClient = 0;
+
+ sFakeComposer->runVSyncAndWait();
+ mBaseFrame.clear();
+ sFakeComposer->clearFrames();
+ ASSERT_EQ(0, sFakeComposer->getFrameCount());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ std::vector<LayerDebugInfo> layers;
+ status_t result = sf->getLayerDebugInfo(&layers);
+ if (result != NO_ERROR) {
+ ALOGE("Failed to get layers %s %d", strerror(-result), result);
+ } else {
+ // If this fails, the test being torn down leaked layers.
+ EXPECT_EQ(0u, layers.size());
+ if (layers.size() > 0) {
+ for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
+ std::cout << to_string(*layer).c_str();
+ }
+ // To ensure the next test has clean slate, will run the class
+ // tear down and setup here.
+ TearDownTestCase();
+ SetUpTestCase();
+ }
+ }
+ ALOGD("TransactionTest::TearDown - complete");
+ }
+
+ void Test_LayerMove() {
+ ALOGD("TransactionTest::LayerMove");
+
+ // The scope opens and closes a global transaction and, at the
+ // same time, makes sure the SurfaceFlinger progresses one frame
+ // after the transaction closes. The results of the transaction
+ // should be available in the latest frame stored by the fake
+ // composer.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 128, 128);
+ // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
+ // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
+ //
+ // sFakeComposer->runVSyncAndWait();
+ }
+
+ fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+ sFakeComposer->runVSyncAndWait();
+
+ ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and
+ // there's no extra frames.
+
+ // NOTE: Frame 0 is produced in the SetUp.
+ auto frame1Ref = mBaseFrame;
+ frame1Ref[FG_LAYER].mDisplayFrame =
+ hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
+ EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+ auto frame2Ref = frame1Ref;
+ frame2Ref[FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+ }
+
+ void Test_LayerResize() {
+ ALOGD("TransactionTest::LayerResize");
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setSize(mFGSurfaceControl, 128, 128);
+ }
+
+ fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+ sFakeComposer->runVSyncAndWait();
+
+ ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and
+ // there's no extra frames.
+
+ auto frame1Ref = mBaseFrame;
+ // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size
+ // posted.
+ EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+ auto frame2Ref = frame1Ref;
+ frame2Ref[FG_LAYER].mSwapCount++;
+ frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
+ frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
+ EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+ }
+
+ void Test_LayerCrop() {
+ // TODO: Add scaling to confirm that crop happens in buffer space?
+ {
+ TransactionScope ts(*sFakeComposer);
+ Rect cropRect(16, 16, 32, 32);
+ ts.setCrop_legacy(mFGSurfaceControl, cropRect);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerSetLayer() {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ // The layers will switch order, but both are rendered because the background layer is
+ // transparent (RGBA8888).
+ std::vector<RenderState> referenceFrame(2);
+ referenceFrame[0] = mBaseFrame[FG_LAYER];
+ referenceFrame[1] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerSetLayerOpaque() {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+ ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
+ layer_state_t::eLayerOpaque);
+ }
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+ // The former foreground layer is now covered with opaque layer - it should have disappeared
+ std::vector<RenderState> referenceFrame(1);
+ referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_SetLayerStack() {
+ ALOGD("TransactionTest::SetLayerStack");
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayerStack(mFGSurfaceControl, 1);
+ }
+
+ // Foreground layer should have disappeared.
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ std::vector<RenderState> refFrame(1);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerShowHide() {
+ ALOGD("TransactionTest::LayerShowHide");
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.hide(mFGSurfaceControl);
+ }
+
+ // Foreground layer should have disappeared.
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ std::vector<RenderState> refFrame(1);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.show(mFGSurfaceControl);
+ }
+
+ // Foreground layer should be back
+ ASSERT_EQ(3, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerSetAlpha() {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 0.75f);
+ }
+
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerSetFlags() {
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
+ layer_state_t::eLayerHidden);
+ }
+
+ // Foreground layer should have disappeared.
+ ASSERT_EQ(2, sFakeComposer->getFrameCount());
+ std::vector<RenderState> refFrame(1);
+ refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+ EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerSetMatrix() {
+ struct matrixTestData {
+ float matrix[4];
+ hwc_transform_t expectedTransform;
+ hwc_rect_t expectedDisplayFrame;
+ };
+
+ // The matrix operates on the display frame and is applied before
+ // the position is added. So, the foreground layer rect is (0, 0,
+ // 64, 64) is first transformed, potentially yielding negative
+ // coordinates and then the position (64, 64) is added yielding
+ // the final on-screen rectangles given.
+
+ const matrixTestData MATRIX_TESTS[7] = // clang-format off
+ {{{-1.f, 0.f, 0.f, 1.f}, HWC_TRANSFORM_FLIP_H, {0, 64, 64, 128}},
+ {{1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_FLIP_V, {64, 0, 128, 64}},
+ {{0.f, 1.f, -1.f, 0.f}, HWC_TRANSFORM_ROT_90, {0, 64, 64, 128}},
+ {{-1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_ROT_180, {0, 0, 64, 64}},
+ {{0.f, -1.f, 1.f, 0.f}, HWC_TRANSFORM_ROT_270, {64, 0, 128, 64}},
+ {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}},
+ {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}};
+ // clang-format on
+ constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
+
+ for (int i = 0; i < TEST_COUNT; i++) {
+ // TODO: How to leverage the HWC2 stringifiers?
+ const matrixTestData& xform = MATRIX_TESTS[i];
+ SCOPED_TRACE(i);
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1], xform.matrix[2],
+ xform.matrix[3]);
+ }
+
+ auto referenceFrame = mBaseFrame;
+ referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
+ referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
+
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+ }
+ }
+
+ void Test_DeferredTransaction() {
+ // Synchronization surface
+ constexpr static int SYNC_LAYER = 2;
+ auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
+ PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(syncSurfaceControl != nullptr);
+ ASSERT_TRUE(syncSurfaceControl->isValid());
+
+ fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
+ ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
+ ts.show(syncSurfaceControl);
+ }
+ auto referenceFrame = mBaseFrame;
+ referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
+ mDisplayWidth - 1, mDisplayHeight - 1));
+ referenceFrame[SYNC_LAYER].mSwapCount = 1;
+ EXPECT_EQ(2, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // set up two deferred transactions on different frames - these should not yield composited
+ // frames
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 0.75);
+ ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+ syncSurfaceControl->getSurface()->getNextFrameNumber());
+ }
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(mFGSurfaceControl, 128, 128);
+ ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+ syncSurfaceControl->getSurface()->getNextFrameNumber() +
+ 1);
+ }
+ EXPECT_EQ(4, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // should trigger the first deferred transaction, but not the second one
+ fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+ sFakeComposer->runVSyncAndWait();
+ EXPECT_EQ(5, sFakeComposer->getFrameCount());
+
+ referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+ referenceFrame[SYNC_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // should show up immediately since it's not deferred
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setAlpha(mFGSurfaceControl, 1.0);
+ }
+ referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
+ EXPECT_EQ(6, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // trigger the second deferred transaction
+ fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+ sFakeComposer->runVSyncAndWait();
+ // TODO: Compute from layer size?
+ referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
+ referenceFrame[SYNC_LAYER].mSwapCount++;
+ EXPECT_EQ(7, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_SetRelativeLayer() {
+ constexpr int RELATIVE_LAYER = 2;
+ auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64,
+ 64, PIXEL_FORMAT_RGBA_8888, 0);
+ fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
+
+ // Now we stack the surface above the foreground surface and make sure it is visible.
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setPosition(relativeSurfaceControl, 64, 64);
+ ts.show(relativeSurfaceControl);
+ ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
+ }
+ auto referenceFrame = mBaseFrame;
+ // NOTE: All three layers will be visible as the surfaces are
+ // transparent because of the RGBA format.
+ referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+ referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
+ EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+ // A call to setLayer will override a call to setRelativeLayer
+ {
+ TransactionScope ts(*sFakeComposer);
+ ts.setLayer(relativeSurfaceControl, 0);
+ }
+
+ // Previous top layer will now appear at the bottom.
+ auto referenceFrame2 = mBaseFrame;
+ referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
+ EXPECT_EQ(3, sFakeComposer->getFrameCount());
+ EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+ }
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mBGSurfaceControl;
@@ -442,944 +1399,609 @@
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;
- static FakeComposerClient* sFakeComposer;
+ static inline FakeComposerClient* sFakeComposer;
};
-FakeComposerClient* TransactionTest::sFakeComposer;
+using TransactionTest_2_1 = TransactionTest<FakeComposerService_2_1>;
-void TransactionTest::SetUpTestCase() {
- // TODO: See TODO comment at DisplayTest::SetUp for background on
- // the lifetime of the FakeComposerClient.
- sFakeComposer = new FakeComposerClient;
- sp<ComposerClient> client = new ComposerClient(sFakeComposer);
- sp<IComposer> fakeService = new FakeComposerService(client);
- (void)fakeService->registerAsService("mock");
-
- android::hardware::ProcessState::self()->startThreadPool();
- android::ProcessState::self()->startThreadPool();
-
- startSurfaceFlinger();
-
- // Fake composer wants to enable VSync injection
- sFakeComposer->onSurfaceFlingerStart();
+TEST_F(TransactionTest_2_1, DISABLED_LayerMove) {
+ Test_LayerMove();
}
-void TransactionTest::TearDownTestCase() {
- // Fake composer needs to release SurfaceComposerClient before the stop.
- sFakeComposer->onSurfaceFlingerStop();
- stopSurfaceFlinger();
- // TODO: This is deleted when the ComposerClient calls
- // removeClient. Devise better lifetime control.
- sFakeComposer = nullptr;
+TEST_F(TransactionTest_2_1, DISABLED_LayerResize) {
+ Test_LayerResize();
}
-void TransactionTest::SetUp() {
- ALOGI("TransactionTest::SetUp");
- mComposerClient = new SurfaceComposerClient;
- ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
- ALOGI("TransactionTest::SetUp - display");
- const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
- ASSERT_FALSE(display == nullptr);
-
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
-
- // Background surface
- mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
- mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mBGSurfaceControl != nullptr);
- ASSERT_TRUE(mBGSurfaceControl->isValid());
- fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
-
- // Foreground surface
- mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(mFGSurfaceControl != nullptr);
- ASSERT_TRUE(mFGSurfaceControl->isValid());
-
- fillSurfaceRGBA8(mFGSurfaceControl, RED);
-
- Transaction t;
- t.setDisplayLayerStack(display, 0);
-
- t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
- t.show(mBGSurfaceControl);
-
- t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
- t.setPosition(mFGSurfaceControl, 64, 64);
- t.show(mFGSurfaceControl);
-
- // Synchronous transaction will stop this thread, so we set up a
- // delayed, off-thread vsync request before closing the
- // transaction. In the test code this is usually done with
- // TransactionScope. Leaving here in the 'vanilla' form for
- // reference.
- ASSERT_EQ(0, sFakeComposer->getFrameCount());
- sFakeComposer->runVSyncAfter(1ms);
- t.apply();
- sFakeComposer->waitUntilFrame(1);
-
- // Reference data. This is what the HWC should see.
- static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
- mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
- mBaseFrame[BG_LAYER].mSwapCount = 1;
- mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
- mBaseFrame[FG_LAYER].mSwapCount = 1;
-
- auto frame = sFakeComposer->getFrameRects(0);
- ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
+TEST_F(TransactionTest_2_1, DISABLED_LayerCrop) {
+ Test_LayerCrop();
}
-void TransactionTest::TearDown() {
- ALOGD("TransactionTest::TearDown");
-
- mComposerClient->dispose();
- mBGSurfaceControl = 0;
- mFGSurfaceControl = 0;
- mComposerClient = 0;
-
- sFakeComposer->runVSyncAndWait();
- mBaseFrame.clear();
- sFakeComposer->clearFrames();
- ASSERT_EQ(0, sFakeComposer->getFrameCount());
-
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- std::vector<LayerDebugInfo> layers;
- status_t result = sf->getLayerDebugInfo(&layers);
- if (result != NO_ERROR) {
- ALOGE("Failed to get layers %s %d", strerror(-result), result);
- } else {
- // If this fails, the test being torn down leaked layers.
- EXPECT_EQ(0u, layers.size());
- if (layers.size() > 0) {
- for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
- std::cout << to_string(*layer).c_str();
- }
- // To ensure the next test has clean slate, will run the class
- // tear down and setup here.
- TearDownTestCase();
- SetUpTestCase();
- }
- }
- ALOGD("TransactionTest::TearDown - complete");
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetLayer) {
+ Test_LayerSetLayer();
}
-TEST_F(TransactionTest, LayerMove) {
- ALOGD("TransactionTest::LayerMove");
-
- // The scope opens and closes a global transaction and, at the
- // same time, makes sure the SurfaceFlinger progresses one frame
- // after the transaction closes. The results of the transaction
- // should be available in the latest frame stored by the fake
- // composer.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 128, 128);
- // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
- // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
- //
- // sFakeComposer->runVSyncAndWait();
- }
-
- fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
- sFakeComposer->runVSyncAndWait();
-
- ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
- // no extra frames.
-
- // NOTE: Frame 0 is produced in the SetUp.
- auto frame1Ref = mBaseFrame;
- frame1Ref[FG_LAYER].mDisplayFrame =
- hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
- EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
-
- auto frame2Ref = frame1Ref;
- frame2Ref[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetLayerOpaque) {
+ Test_LayerSetLayerOpaque();
}
-TEST_F(TransactionTest, LayerResize) {
- ALOGD("TransactionTest::LayerResize");
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- }
-
- fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
- sFakeComposer->runVSyncAndWait();
-
- ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
- // no extra frames.
-
- auto frame1Ref = mBaseFrame;
- // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted.
- EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
-
- auto frame2Ref = frame1Ref;
- frame2Ref[FG_LAYER].mSwapCount++;
- frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
- frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
- EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+TEST_F(TransactionTest_2_1, DISABLED_SetLayerStack) {
+ Test_SetLayerStack();
}
-TEST_F(TransactionTest, LayerCrop) {
- // TODO: Add scaling to confirm that crop happens in buffer space?
- {
- TransactionScope ts(*sFakeComposer);
- Rect cropRect(16, 16, 32, 32);
- ts.setCrop_legacy(mFGSurfaceControl, cropRect);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerShowHide) {
+ Test_LayerShowHide();
}
-TEST_F(TransactionTest, LayerSetLayer) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // The layers will switch order, but both are rendered because the background layer is
- // transparent (RGBA8888).
- std::vector<RenderState> referenceFrame(2);
- referenceFrame[0] = mBaseFrame[FG_LAYER];
- referenceFrame[1] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetAlpha) {
+ Test_LayerSetAlpha();
}
-TEST_F(TransactionTest, LayerSetLayerOpaque) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
- ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
- layer_state_t::eLayerOpaque);
- }
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
- // The former foreground layer is now covered with opaque layer - it should have disappeared
- std::vector<RenderState> referenceFrame(1);
- referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetFlags) {
+ Test_LayerSetFlags();
}
-TEST_F(TransactionTest, SetLayerStack) {
- ALOGD("TransactionTest::SetLayerStack");
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayerStack(mFGSurfaceControl, 1);
- }
-
- // Foreground layer should have disappeared.
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- std::vector<RenderState> refFrame(1);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetMatrix) {
+ Test_LayerSetMatrix();
}
-TEST_F(TransactionTest, LayerShowHide) {
- ALOGD("TransactionTest::LayerShowHide");
- {
- TransactionScope ts(*sFakeComposer);
- ts.hide(mFGSurfaceControl);
- }
-
- // Foreground layer should have disappeared.
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- std::vector<RenderState> refFrame(1);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mFGSurfaceControl);
- }
-
- // Foreground layer should be back
- ASSERT_EQ(3, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_DeferredTransaction) {
+ Test_DeferredTransaction();
}
-TEST_F(TransactionTest, LayerSetAlpha) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 0.75f);
- }
-
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_SetRelativeLayer) {
+ Test_SetRelativeLayer();
}
-TEST_F(TransactionTest, LayerSetFlags) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
- layer_state_t::eLayerHidden);
- }
+template <typename FakeComposerService>
+class ChildLayerTest : public TransactionTest<FakeComposerService> {
+ using Base = TransactionTest<FakeComposerService>;
- // Foreground layer should have disappeared.
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- std::vector<RenderState> refFrame(1);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(TransactionTest, LayerSetMatrix) {
- struct matrixTestData {
- float matrix[4];
- hwc_transform_t expectedTransform;
- hwc_rect_t expectedDisplayFrame;
- };
-
- // The matrix operates on the display frame and is applied before
- // the position is added. So, the foreground layer rect is (0, 0,
- // 64, 64) is first transformed, potentially yielding negative
- // coordinates and then the position (64, 64) is added yielding
- // the final on-screen rectangles given.
-
- const matrixTestData MATRIX_TESTS[7] = // clang-format off
- {{{-1.f, 0.f, 0.f, 1.f}, HWC_TRANSFORM_FLIP_H, {0, 64, 64, 128}},
- {{1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_FLIP_V, {64, 0, 128, 64}},
- {{0.f, 1.f, -1.f, 0.f}, HWC_TRANSFORM_ROT_90, {0, 64, 64, 128}},
- {{-1.f, 0.f, 0.f, -1.f}, HWC_TRANSFORM_ROT_180, {0, 0, 64, 64}},
- {{0.f, -1.f, 1.f, 0.f}, HWC_TRANSFORM_ROT_270, {64, 0, 128, 64}},
- {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_H_ROT_90, {64, 64, 128, 128}},
- {{0.f, 1.f, 1.f, 0.f}, HWC_TRANSFORM_FLIP_V_ROT_90, {64, 64, 128, 128}}};
- // clang-format on
- constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
-
- for (int i = 0; i < TEST_COUNT; i++) {
- // TODO: How to leverage the HWC2 stringifiers?
- const matrixTestData& xform = MATRIX_TESTS[i];
- SCOPED_TRACE(i);
- {
- TransactionScope ts(*sFakeComposer);
- ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1],
- xform.matrix[2], xform.matrix[3]);
- }
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
- referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
-
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
- }
-}
-
-#if 0
-TEST_F(TransactionTest, LayerSetMatrix2) {
- {
- TransactionScope ts(*sFakeComposer);
- // TODO: PLEASE SPEC THE FUNCTION!
- ts.setMatrix(mFGSurfaceControl, 0.11f, 0.123f,
- -2.33f, 0.22f);
- }
- auto referenceFrame = mBaseFrame;
- // TODO: Is this correct for sure?
- //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90;
-
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-#endif
-
-TEST_F(TransactionTest, DeferredTransaction) {
- // Synchronization surface
- constexpr static int SYNC_LAYER = 2;
- auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
- PIXEL_FORMAT_RGBA_8888, 0);
- ASSERT_TRUE(syncSurfaceControl != nullptr);
- ASSERT_TRUE(syncSurfaceControl->isValid());
-
- fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
- ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
- ts.show(syncSurfaceControl);
- }
- auto referenceFrame = mBaseFrame;
- referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
- mDisplayWidth - 1, mDisplayHeight - 1));
- referenceFrame[SYNC_LAYER].mSwapCount = 1;
- EXPECT_EQ(2, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // set up two deferred transactions on different frames - these should not yield composited
- // frames
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 0.75);
- ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
- syncSurfaceControl->getSurface()->getNextFrameNumber());
- }
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 128, 128);
- ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
- syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
- }
- EXPECT_EQ(4, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // should trigger the first deferred transaction, but not the second one
- fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
- sFakeComposer->runVSyncAndWait();
- EXPECT_EQ(5, sFakeComposer->getFrameCount());
-
- referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
- referenceFrame[SYNC_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // should show up immediately since it's not deferred
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 1.0);
- }
- referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
- EXPECT_EQ(6, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // trigger the second deferred transaction
- fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
- sFakeComposer->runVSyncAndWait();
- // TODO: Compute from layer size?
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
- referenceFrame[SYNC_LAYER].mSwapCount++;
- EXPECT_EQ(7, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(TransactionTest, SetRelativeLayer) {
- constexpr int RELATIVE_LAYER = 2;
- auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64,
- PIXEL_FORMAT_RGBA_8888, 0);
- fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
-
- // Now we stack the surface above the foreground surface and make sure it is visible.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(relativeSurfaceControl, 64, 64);
- ts.show(relativeSurfaceControl);
- ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
- }
- auto referenceFrame = mBaseFrame;
- // NOTE: All three layers will be visible as the surfaces are
- // transparent because of the RGBA format.
- referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
- referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- // A call to setLayer will override a call to setRelativeLayer
- {
- TransactionScope ts(*sFakeComposer);
- ts.setLayer(relativeSurfaceControl, 0);
- }
-
- // Previous top layer will now appear at the bottom.
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
- EXPECT_EQ(3, sFakeComposer->getFrameCount());
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
-}
-
-class ChildLayerTest : public TransactionTest {
protected:
constexpr static int CHILD_LAYER = 2;
void SetUp() override {
- TransactionTest::SetUp();
- mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ Base::SetUp();
+ mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0,
+ Base::mFGSurfaceControl.get());
fillSurfaceRGBA8(mChild, LIGHT_GRAY);
- sFakeComposer->runVSyncAndWait();
- mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
- mBaseFrame[CHILD_LAYER].mSwapCount = 1;
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+ Base::sFakeComposer->runVSyncAndWait();
+ Base::mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+ Base::mBaseFrame[CHILD_LAYER].mSwapCount = 1;
+ ASSERT_EQ(2, Base::sFakeComposer->getFrameCount());
+ ASSERT_TRUE(framesAreSame(Base::mBaseFrame, Base::sFakeComposer->getLatestFrame()));
}
+
void TearDown() override {
mChild = 0;
- TransactionTest::TearDown();
+ Base::TearDown();
+ }
+
+ void Test_Positioning() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 10, 10);
+ // Move to the same position as in the original setup.
+ ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+ }
+
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ }
+
+ auto referenceFrame2 = Base::mBaseFrame;
+ referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
+ referenceFrame2[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_Cropping() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 5, 5));
+ }
+ // NOTE: The foreground surface would be occluded by the child
+ // now, but is included in the stack because the child is
+ // transparent.
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+ referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+ referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_Constraints() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ ts.setPosition(mChild, 63, 63);
+ }
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
+ referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_Scaling() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ }
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setMatrix(Base::mFGSurfaceControl, 2.0, 0, 0, 2.0);
+ }
+
+ auto referenceFrame2 = Base::mBaseFrame;
+ referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+ referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+ EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerAlpha() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ ts.setAlpha(mChild, 0.5);
+ }
+
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setAlpha(Base::mFGSurfaceControl, 0.5);
+ }
+
+ auto referenceFrame2 = referenceFrame;
+ referenceFrame2[Base::FG_LAYER].mPlaneAlpha = 0.5f;
+ referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_ReparentChildren() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 10, 10);
+ ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+ }
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.reparentChildren(Base::mFGSurfaceControl, Base::mBGSurfaceControl->getHandle());
+ }
+
+ auto referenceFrame2 = referenceFrame;
+ referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_DetachChildrenSameClient() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 10, 10);
+ ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+ }
+
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ ts.detachChildren(Base::mFGSurfaceControl);
+ }
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+ ts.hide(mChild);
+ }
+
+ std::vector<RenderState> refFrame(2);
+ refFrame[Base::BG_LAYER] = Base::mBaseFrame[Base::BG_LAYER];
+ refFrame[Base::FG_LAYER] = Base::mBaseFrame[Base::FG_LAYER];
+
+ EXPECT_TRUE(framesAreSame(refFrame, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_DetachChildrenDifferentClient() {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0,
+ Base::mFGSurfaceControl.get());
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+ fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.hide(mChild);
+ ts.show(childNewClient);
+ ts.setPosition(childNewClient, 10, 10);
+ ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+ }
+
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+ referenceFrame[CHILD_LAYER].mDisplayFrame =
+ hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.detachChildren(Base::mFGSurfaceControl);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ }
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+ ts.setPosition(childNewClient, 0, 0);
+ ts.hide(childNewClient);
+ }
+
+ // Nothing should have changed. The child control becomes a no-op
+ // zombie on detach. See comments for detachChildren in the
+ // SurfaceControl.h file.
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_InheritNonTransformScalingFromParent() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ }
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setOverrideScalingMode(Base::mFGSurfaceControl,
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // We cause scaling by 2.
+ ts.setSize(Base::mFGSurfaceControl, 128, 128);
+ }
+
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+ referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+ referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ // Regression test for b/37673612
+ void Test_ChildrenWithParentBufferTransform() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(mChild);
+ ts.setPosition(mChild, 0, 0);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ }
+
+ // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+ // the WM specified state size.
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setSize(Base::mFGSurfaceControl, 128, 64);
+ }
+
+ sp<Surface> s = Base::mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
+ Base::sFakeComposer->runVSyncAndWait();
+
+ // The child should still be in the same place and not have any strange scaling as in
+ // b/37673612.
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
+ referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
+ referenceFrame[Base::FG_LAYER].mSwapCount++;
+ referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_Bug36858924() {
+ // Destroy the child layer
+ mChild.clear();
+
+ // Now recreate it as hidden
+ mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eHidden,
+ Base::mFGSurfaceControl.get());
+
+ // Show the child layer in a deferred transaction
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.deferTransactionUntil_legacy(mChild, Base::mFGSurfaceControl->getHandle(),
+ Base::mFGSurfaceControl->getSurface()
+ ->getNextFrameNumber());
+ ts.show(mChild);
+ }
+
+ // Render the foreground surface a few times
+ //
+ // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the
+ // third frame because SurfaceFlinger would never process the deferred transaction and would
+ // therefore never acquire/release the first buffer
+ ALOGI("Filling 1");
+ fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN);
+ Base::sFakeComposer->runVSyncAndWait();
+ ALOGI("Filling 2");
+ fillSurfaceRGBA8(Base::mFGSurfaceControl, BLUE);
+ Base::sFakeComposer->runVSyncAndWait();
+ ALOGI("Filling 3");
+ fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
+ Base::sFakeComposer->runVSyncAndWait();
+ ALOGI("Filling 4");
+ fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN);
+ Base::sFakeComposer->runVSyncAndWait();
}
sp<SurfaceControl> mChild;
};
-TEST_F(ChildLayerTest, Positioning) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 10, 10);
- // Move to the same position as in the original setup.
- ts.setPosition(mFGSurfaceControl, 64, 64);
- }
+using ChildLayerTest_2_1 = ChildLayerTest<FakeComposerService_2_1>;
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame =
- hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- }
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
- referenceFrame2[CHILD_LAYER].mDisplayFrame =
- hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Positioning) {
+ Test_Positioning();
}
-TEST_F(ChildLayerTest, Cropping) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
- }
- // NOTE: The foreground surface would be occluded by the child
- // now, but is included in the stack because the child is
- // transparent.
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Cropping) {
+ Test_Cropping();
}
-TEST_F(ChildLayerTest, Constraints) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setPosition(mChild, 63, 63);
- }
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Constraints) {
+ Test_Constraints();
}
-TEST_F(ChildLayerTest, Scaling) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- }
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0);
- }
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
- referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Scaling) {
+ Test_Scaling();
}
-TEST_F(ChildLayerTest, LayerAlpha) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setAlpha(mChild, 0.5);
- }
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 0.5);
- }
-
- auto referenceFrame2 = referenceFrame;
- referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
- referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_LayerAlpha) {
+ Test_LayerAlpha();
}
-TEST_F(ChildLayerTest, ReparentChildren) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 10, 10);
- ts.setPosition(mFGSurfaceControl, 64, 64);
- }
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame =
- hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
- }
-
- auto referenceFrame2 = referenceFrame;
- referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
- referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_ReparentChildren) {
+ Test_ReparentChildren();
}
-TEST_F(ChildLayerTest, DetachChildrenSameClient) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 10, 10);
- ts.setPosition(mFGSurfaceControl, 64, 64);
- }
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame =
- hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.detachChildren(mFGSurfaceControl);
- }
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 64, 64);
- ts.hide(mChild);
- }
-
- std::vector<RenderState> refFrame(2);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
- refFrame[FG_LAYER] = mBaseFrame[FG_LAYER];
-
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_DetachChildrenSameClient) {
+ Test_DetachChildrenSameClient();
}
-TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
- sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> childNewClient =
- newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- ASSERT_TRUE(childNewClient != nullptr);
- ASSERT_TRUE(childNewClient->isValid());
- fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.hide(mChild);
- ts.show(childNewClient);
- ts.setPosition(childNewClient, 10, 10);
- ts.setPosition(mFGSurfaceControl, 64, 64);
- }
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame =
- hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.detachChildren(mFGSurfaceControl);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- }
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setPosition(mFGSurfaceControl, 64, 64);
- ts.setPosition(childNewClient, 0, 0);
- ts.hide(childNewClient);
- }
-
- // Nothing should have changed. The child control becomes a no-op
- // zombie on detach. See comments for detachChildren in the
- // SurfaceControl.h file.
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_DetachChildrenDifferentClient) {
+ Test_DetachChildrenDifferentClient();
}
-TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- }
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // We cause scaling by 2.
- ts.setSize(mFGSurfaceControl, 128, 128);
- }
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
- referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_InheritNonTransformScalingFromParent) {
+ Test_InheritNonTransformScalingFromParent();
}
// Regression test for b/37673612
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- }
-
- // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
- // the WM specified state size.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 64);
- }
-
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- fillSurfaceRGBA8(mFGSurfaceControl, RED);
- sFakeComposer->runVSyncAndWait();
-
- // The child should still be in the same place and not have any strange scaling as in
- // b/37673612.
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
- referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
- referenceFrame[FG_LAYER].mSwapCount++;
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) {
+ Test_ChildrenWithParentBufferTransform();
}
-TEST_F(ChildLayerTest, Bug36858924) {
- // Destroy the child layer
- mChild.clear();
-
- // Now recreate it as hidden
- mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden,
- mFGSurfaceControl.get());
-
- // Show the child layer in a deferred transaction
- {
- TransactionScope ts(*sFakeComposer);
- ts.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber());
- ts.show(mChild);
- }
-
- // Render the foreground surface a few times
- //
- // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
- // frame because SurfaceFlinger would never process the deferred transaction and would therefore
- // never acquire/release the first buffer
- ALOGI("Filling 1");
- fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
- sFakeComposer->runVSyncAndWait();
- ALOGI("Filling 2");
- fillSurfaceRGBA8(mFGSurfaceControl, BLUE);
- sFakeComposer->runVSyncAndWait();
- ALOGI("Filling 3");
- fillSurfaceRGBA8(mFGSurfaceControl, RED);
- sFakeComposer->runVSyncAndWait();
- ALOGI("Filling 4");
- fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
- sFakeComposer->runVSyncAndWait();
+TEST_F(ChildLayerTest_2_1, DISABLED_Bug36858924) {
+ Test_Bug36858924();
}
-class ChildColorLayerTest : public ChildLayerTest {
+template <typename FakeComposerService>
+class ChildColorLayerTest : public ChildLayerTest<FakeComposerService> {
+ using Base = ChildLayerTest<FakeComposerService>;
+
protected:
void SetUp() override {
- TransactionTest::SetUp();
- mChild = mComposerClient->createSurface(String8("Child surface"), 0, 0,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor,
- mFGSurfaceControl.get());
+ Base::SetUp();
+ Base::mChild =
+ Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceEffect,
+ Base::mFGSurfaceControl.get());
{
- TransactionScope ts(*sFakeComposer);
- ts.setColor(mChild,
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setColor(Base::mChild,
{LIGHT_GRAY.r / 255.0f, LIGHT_GRAY.g / 255.0f, LIGHT_GRAY.b / 255.0f});
- ts.setCrop_legacy(mChild, Rect(0, 0, 10, 10));
+ ts.setCrop_legacy(Base::mChild, Rect(0, 0, 10, 10));
}
- sFakeComposer->runVSyncAndWait();
- mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
- mBaseFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.0f, 0.0f, 0.0f, 0.0f};
- mBaseFrame[CHILD_LAYER].mSwapCount = 0;
- ASSERT_EQ(2, sFakeComposer->getFrameCount());
- ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+ Base::sFakeComposer->runVSyncAndWait();
+ Base::mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+ Base::mBaseFrame[Base::CHILD_LAYER].mSourceCrop = hwc_frect_t{0.0f, 0.0f, 0.0f, 0.0f};
+ Base::mBaseFrame[Base::CHILD_LAYER].mSwapCount = 0;
+ ASSERT_EQ(2, Base::sFakeComposer->getFrameCount());
+ ASSERT_TRUE(framesAreSame(Base::mBaseFrame, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerAlpha() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(Base::mChild);
+ ts.setPosition(Base::mChild, 0, 0);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ ts.setAlpha(Base::mChild, 0.5);
+ }
+
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[Base::CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ referenceFrame[Base::CHILD_LAYER].mPlaneAlpha = 0.5f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setAlpha(Base::mFGSurfaceControl, 0.5);
+ }
+
+ auto referenceFrame2 = referenceFrame;
+ referenceFrame2[Base::FG_LAYER].mPlaneAlpha = 0.5f;
+ referenceFrame2[Base::CHILD_LAYER].mPlaneAlpha = 0.25f;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_LayerZeroAlpha() {
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.show(Base::mChild);
+ ts.setPosition(Base::mChild, 0, 0);
+ ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+ ts.setAlpha(Base::mChild, 0.5);
+ }
+
+ auto referenceFrame = Base::mBaseFrame;
+ referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+ referenceFrame[Base::CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+ referenceFrame[Base::CHILD_LAYER].mPlaneAlpha = 0.5f;
+ EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setAlpha(Base::mFGSurfaceControl, 0.0f);
+ }
+
+ std::vector<RenderState> refFrame(1);
+ refFrame[Base::BG_LAYER] = Base::mBaseFrame[Base::BG_LAYER];
+
+ EXPECT_TRUE(framesAreSame(refFrame, Base::sFakeComposer->getLatestFrame()));
}
};
-TEST_F(ChildColorLayerTest, LayerAlpha) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setAlpha(mChild, 0.5);
- }
+using ChildColorLayerTest_2_1 = ChildColorLayerTest<FakeComposerService_2_1>;
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 0.5);
- }
-
- auto referenceFrame2 = referenceFrame;
- referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
- referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerAlpha) {
+ Test_LayerAlpha();
}
-TEST_F(ChildColorLayerTest, LayerZeroAlpha) {
- {
- TransactionScope ts(*sFakeComposer);
- ts.show(mChild);
- ts.setPosition(mChild, 0, 0);
- ts.setPosition(mFGSurfaceControl, 0, 0);
- ts.setAlpha(mChild, 0.5);
- }
-
- auto referenceFrame = mBaseFrame;
- referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
- referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
- referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
- EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setAlpha(mFGSurfaceControl, 0.0f);
- }
-
- std::vector<RenderState> refFrame(1);
- refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
-
- EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerZeroAlpha) {
+ Test_LayerZeroAlpha();
}
-class LatchingTest : public TransactionTest {
+template <typename FakeComposerService>
+class LatchingTest : public TransactionTest<FakeComposerService> {
+ using Base = TransactionTest<FakeComposerService>;
+
protected:
- void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); }
+ void lockAndFillFGBuffer() { fillSurfaceRGBA8(Base::mFGSurfaceControl, RED, false); }
void unlockFGBuffer() {
- sp<Surface> s = mFGSurfaceControl->getSurface();
+ sp<Surface> s = Base::mFGSurfaceControl->getSurface();
ASSERT_EQ(NO_ERROR, s->unlockAndPost());
- sFakeComposer->runVSyncAndWait();
+ Base::sFakeComposer->runVSyncAndWait();
}
void completeFGResize() {
- fillSurfaceRGBA8(mFGSurfaceControl, RED);
- sFakeComposer->runVSyncAndWait();
+ fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
+ Base::sFakeComposer->runVSyncAndWait();
}
void restoreInitialState() {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 64, 64);
- ts.setPosition(mFGSurfaceControl, 64, 64);
- ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setSize(Base::mFGSurfaceControl, 64, 64);
+ ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+ ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 64, 64));
+ }
+
+ void Test_SurfacePositionLatching() {
+ // By default position can be updated even while
+ // a resize is pending.
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setSize(Base::mFGSurfaceControl, 32, 32);
+ ts.setPosition(Base::mFGSurfaceControl, 100, 100);
+ }
+
+ // The size should not have updated as we have not provided a new buffer.
+ auto referenceFrame1 = Base::mBaseFrame;
+ referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
+ EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame()));
+
+ restoreInitialState();
+
+ completeFGResize();
+
+ auto referenceFrame2 = Base::mBaseFrame;
+ referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
+ referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+ referenceFrame2[Base::FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+ }
+
+ void Test_CropLatching() {
+ // Normally the crop applies immediately even while a resize is pending.
+ {
+ TransactionScope ts(*Base::sFakeComposer);
+ ts.setSize(Base::mFGSurfaceControl, 128, 128);
+ ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 63, 63));
+ }
+
+ auto referenceFrame1 = Base::mBaseFrame;
+ referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+ referenceFrame1[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+ EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame()));
+
+ restoreInitialState();
+
+ completeFGResize();
+
+ auto referenceFrame2 = Base::mBaseFrame;
+ referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+ referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+ referenceFrame2[Base::FG_LAYER].mSwapCount++;
+ EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
}
};
-TEST_F(LatchingTest, SurfacePositionLatching) {
- // By default position can be updated even while
- // a resize is pending.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 32, 32);
- ts.setPosition(mFGSurfaceControl, 100, 100);
- }
+using LatchingTest_2_1 = LatchingTest<FakeComposerService_2_1>;
- // The size should not have updated as we have not provided a new buffer.
- auto referenceFrame1 = mBaseFrame;
- referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
- EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- // Now we repeat with setGeometryAppliesWithResize
- // and verify the position DOESN'T latch.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setSize(mFGSurfaceControl, 32, 32);
- ts.setPosition(mFGSurfaceControl, 100, 100);
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
- referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
- referenceFrame2[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(LatchingTest_2_1, DISABLED_SurfacePositionLatching) {
+ Test_SurfacePositionLatching();
}
-TEST_F(LatchingTest, CropLatching) {
- // Normally the crop applies immediately even while a resize is pending.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
- }
-
- auto referenceFrame1 = mBaseFrame;
- referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
- referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
- EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
- restoreInitialState();
-
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
- completeFGResize();
-
- auto referenceFrame2 = mBaseFrame;
- referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
- referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
- referenceFrame2[FG_LAYER].mSwapCount++;
- EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(LatchingTest_2_1, DISABLED_CropLatching) {
+ Test_CropLatching();
}
} // namespace
@@ -1387,8 +2009,11 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment;
+ auto* fakeEnvironment = new sftest::FakeHwcEnvironment;
::testing::AddGlobalTestEnvironment(fakeEnvironment);
::testing::InitGoogleMock(&argc, argv);
return RUN_ALL_TESTS();
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Android.bp b/services/surfaceflinger/tests/hwc2/Android.bp
deleted file mode 100644
index 1c8e396..0000000
--- a/services/surfaceflinger/tests/hwc2/Android.bp
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-cc_test {
- name: "test-hwc2",
- defaults: ["surfaceflinger_defaults"],
- cflags: [
- "-DEGL_EGLEXT_PROTOTYPES",
- "-DGL_GLEXT_PROTOTYPES",
- "-fno-builtin",
- "-fstack-protector-all",
- "-g",
- "-Wextra",
- ],
- srcs: [
- "Hwc2Test.cpp",
- "Hwc2TestProperties.cpp",
- "Hwc2TestLayer.cpp",
- "Hwc2TestLayers.cpp",
- "Hwc2TestBuffer.cpp",
- "Hwc2TestClientTarget.cpp",
- "Hwc2TestVirtualDisplay.cpp",
- "Hwc2TestPixelComparator.cpp",
- ],
- static_libs: [
- "libadf",
- "libadfhwc",
- "libbase",
- "libmath",
- ],
- shared_libs: [
- "android.hardware.graphics.common@1.1",
- "libcutils",
- "libEGL",
- "libGLESv2",
- "libgui",
- "libhardware",
- "libhwui",
- "liblog",
- "libsync",
- "libui",
- "libutils",
- ],
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
deleted file mode 100644
index 13774b4..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ /dev/null
@@ -1,4772 +0,0 @@
-/*
- * Copyright (C) 2016 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 <array>
-#include <unordered_set>
-#include <unordered_map>
-#include <gtest/gtest.h>
-#include <dlfcn.h>
-#include <android-base/unique_fd.h>
-#include <hardware/hardware.h>
-#include <sync/sync.h>
-#include <ui/GraphicTypes.h>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestLayer.h"
-#include "Hwc2TestLayers.h"
-#include "Hwc2TestClientTarget.h"
-#include "Hwc2TestVirtualDisplay.h"
-
-using android::ui::ColorMode;
-using android::ui::Dataspace;
-
-void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int32_t connected);
-void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int64_t timestamp);
-
-class Hwc2Test : public testing::Test {
-public:
-
- virtual void SetUp()
- {
- hw_module_t const* hwc2Module;
-
- int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwc2Module);
- ASSERT_GE(err, 0) << "failed to get hwc hardware module: "
- << strerror(-err);
-
- /* The following method will fail if you have not run
- * "adb shell stop" */
- err = hwc2_open(hwc2Module, &mHwc2Device);
- ASSERT_GE(err, 0) << "failed to open hwc hardware module: "
- << strerror(-err);
-
- populateDisplays();
- }
-
- virtual void TearDown()
- {
-
- for (auto itr = mLayers.begin(); itr != mLayers.end();) {
- hwc2_display_t display = itr->first;
- hwc2_layer_t layer = itr->second;
- itr++;
- /* Destroys and removes the layer from mLayers */
- destroyLayer(display, layer);
- }
-
- for (auto itr = mActiveDisplays.begin(); itr != mActiveDisplays.end();) {
- hwc2_display_t display = *itr;
- itr++;
- /* Sets power mode to off and removes the display from
- * mActiveDisplays */
- setPowerMode(display, HWC2_POWER_MODE_OFF);
- }
-
- for (auto itr = mVirtualDisplays.begin(); itr != mVirtualDisplays.end();) {
- hwc2_display_t display = *itr;
- itr++;
- /* Destroys virtual displays */
- destroyVirtualDisplay(display);
- }
-
- if (mHwc2Device)
- hwc2_close(mHwc2Device);
- }
-
- void registerCallback(hwc2_callback_descriptor_t descriptor,
- hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_REGISTER_CALLBACK>(
- getFunction(HWC2_FUNCTION_REGISTER_CALLBACK));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, descriptor,
- callbackData, pointer));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to register callback";
- }
- }
-
- void getDisplayType(hwc2_display_t display, hwc2_display_type_t* outType,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_TYPE>(
- getFunction(HWC2_FUNCTION_GET_DISPLAY_TYPE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- reinterpret_cast<int32_t*>(outType)));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display type";
- }
- }
-
- /* If the populateDisplays function is still receiving displays and the
- * display is connected, the display handle is stored in mDisplays. */
- void hotplugCallback(hwc2_display_t display, int32_t connected)
- {
- std::lock_guard<std::mutex> lock(mHotplugMutex);
-
- if (mHotplugStatus != Hwc2TestHotplugStatus::Receiving)
- return;
-
- if (connected == HWC2_CONNECTION_CONNECTED)
- mDisplays.insert(display);
-
- mHotplugCv.notify_all();
- }
-
- void createLayer(hwc2_display_t display, hwc2_layer_t* outLayer,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_CREATE_LAYER>(
- getFunction(HWC2_FUNCTION_CREATE_LAYER));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- outLayer));
-
- if (err == HWC2_ERROR_NONE)
- mLayers.insert(std::make_pair(display, *outLayer));
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer";
- }
- }
-
- void destroyLayer(hwc2_display_t display, hwc2_layer_t layer,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_LAYER>(
- getFunction(HWC2_FUNCTION_DESTROY_LAYER));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer));
-
- if (err == HWC2_ERROR_NONE)
- mLayers.erase(std::make_pair(display, layer));
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy layer "
- << layer;
- }
- }
-
- void getDisplayAttribute(hwc2_display_t display, hwc2_config_t config,
- hwc2_attribute_t attribute, int32_t* outValue,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
- getFunction(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config,
- attribute, outValue));
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display attribute "
- << getAttributeName(attribute) << " for config " << config;
- }
- }
-
- void getDisplayConfigs(hwc2_display_t display,
- std::vector<hwc2_config_t>* outConfigs,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_CONFIGS>(
- getFunction(HWC2_FUNCTION_GET_DISPLAY_CONFIGS));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t numConfigs = 0;
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numConfigs, nullptr));
-
- if (err == HWC2_ERROR_NONE) {
- outConfigs->resize(numConfigs);
-
- err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numConfigs, outConfigs->data()));
- }
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get configs for"
- " display " << display;
- }
- }
-
- void getActiveConfig(hwc2_display_t display, hwc2_config_t* outConfig,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_ACTIVE_CONFIG>(
- getFunction(HWC2_FUNCTION_GET_ACTIVE_CONFIG));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- outConfig));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get active config on"
- " display " << display;
- }
- }
-
- void setActiveConfig(hwc2_display_t display, hwc2_config_t config,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_ACTIVE_CONFIG>(
- getFunction(HWC2_FUNCTION_SET_ACTIVE_CONFIG));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set active config "
- << config;
- }
- }
-
- void getDozeSupport(hwc2_display_t display, int32_t* outSupport,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_DOZE_SUPPORT>(
- getFunction(HWC2_FUNCTION_GET_DOZE_SUPPORT));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- outSupport));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get doze support on"
- " display " << display;
- }
- }
-
- void setPowerMode(hwc2_display_t display, hwc2_power_mode_t mode,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_POWER_MODE>(
- getFunction(HWC2_FUNCTION_SET_POWER_MODE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- mode));
- if (outErr) {
- *outErr = err;
- if (err != HWC2_ERROR_NONE)
- return;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set power mode "
- << getPowerModeName(mode) << " on display " << display;
- }
-
- if (mode == HWC2_POWER_MODE_OFF) {
- mActiveDisplays.erase(display);
- } else {
- mActiveDisplays.insert(display);
- }
- }
-
- void setVsyncEnabled(hwc2_display_t display, hwc2_vsync_t enabled,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_VSYNC_ENABLED>(
- getFunction(HWC2_FUNCTION_SET_VSYNC_ENABLED));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- enabled));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set vsync enabled "
- << getVsyncName(enabled);
- }
- }
-
- void vsyncCallback(hwc2_display_t display, int64_t timestamp)
- {
- std::lock_guard<std::mutex> lock(mVsyncMutex);
- mVsyncDisplay = display;
- mVsyncTimestamp = timestamp;
- mVsyncCv.notify_all();
- }
-
- void getDisplayName(hwc2_display_t display, std::string* outName,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_NAME>(
- getFunction(HWC2_FUNCTION_GET_DISPLAY_NAME));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t size = 0;
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size,
- nullptr));
-
- if (err == HWC2_ERROR_NONE) {
- std::vector<char> name(size);
-
- err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size,
- name.data()));
-
- outName->assign(name.data());
- }
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display name for "
- << display;
- }
- }
-
- void setLayerCompositionType(hwc2_display_t display, hwc2_layer_t layer,
- hwc2_composition_t composition, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
- getFunction(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- composition));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer composition"
- " type " << getCompositionName(composition);
- }
- }
-
- void setCursorPosition(hwc2_display_t display, hwc2_layer_t layer,
- int32_t x, int32_t y, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_CURSOR_POSITION>(
- getFunction(HWC2_FUNCTION_SET_CURSOR_POSITION));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, x,
- y));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_TRUE((err == HWC2_ERROR_NONE) ||
- (err == HWC2_ERROR_BAD_LAYER)) <<
- "failed to set cursor position";
- }
- }
-
- void setLayerBlendMode(hwc2_display_t display, hwc2_layer_t layer,
- hwc2_blend_mode_t mode, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BLEND_MODE>(
- getFunction(HWC2_FUNCTION_SET_LAYER_BLEND_MODE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- mode));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer blend mode "
- << getBlendModeName(mode);
- }
- }
-
- void setLayerBuffer(hwc2_display_t display, hwc2_layer_t layer,
- buffer_handle_t buffer, int32_t acquireFence,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BUFFER>(
- getFunction(HWC2_FUNCTION_SET_LAYER_BUFFER));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- buffer, acquireFence));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer buffer";
- }
- }
-
- void setLayerColor(hwc2_display_t display, hwc2_layer_t layer,
- hwc_color_t color, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COLOR>(
- getFunction(HWC2_FUNCTION_SET_LAYER_COLOR));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- color));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer color";
- }
- }
-
- void setLayerDataspace(hwc2_display_t display, hwc2_layer_t layer,
- Dataspace dataspace, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DATASPACE>(
- getFunction(HWC2_FUNCTION_SET_LAYER_DATASPACE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- layer, static_cast<int>(dataspace)));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer dataspace";
- }
- }
-
- void setLayerDisplayFrame(hwc2_display_t display, hwc2_layer_t layer,
- const hwc_rect_t& displayFrame, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
- getFunction(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- displayFrame));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer display"
- " frame";
- }
- }
-
- void setLayerPlaneAlpha(hwc2_display_t display, hwc2_layer_t layer,
- float alpha, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
- getFunction(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- alpha));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer plane alpha "
- << alpha;
- }
- }
-
- void setLayerSourceCrop(hwc2_display_t display, hwc2_layer_t layer,
- const hwc_frect_t& sourceCrop, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
- getFunction(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- sourceCrop));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer source crop";
- }
- }
-
- void setLayerSurfaceDamage(hwc2_display_t display, hwc2_layer_t layer,
- const hwc_region_t& surfaceDamage, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
- getFunction(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- surfaceDamage));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer surface"
- " damage";
- }
- }
-
- void setLayerTransform(hwc2_display_t display, hwc2_layer_t layer,
- hwc_transform_t transform, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_TRANSFORM>(
- getFunction(HWC2_FUNCTION_SET_LAYER_TRANSFORM));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- transform));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer transform "
- << getTransformName(transform);
- }
- }
-
- void setLayerVisibleRegion(hwc2_display_t display, hwc2_layer_t layer,
- const hwc_region_t& visibleRegion, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
- getFunction(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- visibleRegion));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer visible"
- " region";
- }
- }
-
- void setLayerZOrder(hwc2_display_t display, hwc2_layer_t layer,
- uint32_t zOrder, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_Z_ORDER>(
- getFunction(HWC2_FUNCTION_SET_LAYER_Z_ORDER));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
- zOrder));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer z order "
- << zOrder;
- }
- }
-
- void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes,
- uint32_t* outNumRequests, hwc2_error_t* outErr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_VALIDATE_DISPLAY>(
- getFunction(HWC2_FUNCTION_VALIDATE_DISPLAY));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- *outErr = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- outNumTypes, outNumRequests));
- }
-
- void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes,
- uint32_t* outNumRequests, bool* outHasChanges)
- {
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- EXPECT_NO_FATAL_FAILURE(validateDisplay(display, outNumTypes,
- outNumRequests, &err));
-
- if (err != HWC2_ERROR_HAS_CHANGES) {
- *outHasChanges = false;
- EXPECT_EQ(err, HWC2_ERROR_NONE) << "failed to validate display";
- } else {
- *outHasChanges = true;
- }
- }
-
- void getDisplayRequests(hwc2_display_t display,
- hwc2_display_request_t* outDisplayRequests,
- std::vector<hwc2_layer_t>* outLayers,
- std::vector<hwc2_layer_request_t>* outLayerRequests,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_REQUESTS>(
- getFunction(HWC2_FUNCTION_GET_DISPLAY_REQUESTS));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t numElements = 0;
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- reinterpret_cast<int32_t*>(outDisplayRequests), &numElements,
- nullptr, nullptr));
-
- if (err == HWC2_ERROR_NONE && numElements > 0) {
- outLayers->resize(numElements);
- outLayerRequests->resize(numElements);
-
- err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- reinterpret_cast<int32_t*>(outDisplayRequests), &numElements,
- reinterpret_cast<uint64_t*>(outLayers->data()),
- reinterpret_cast<int32_t*>(outLayerRequests->data())));
- }
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display requests";
- }
- }
-
- void handleRequests(hwc2_display_t display,
- const std::vector<hwc2_layer_t>& layers, uint32_t numRequests,
- std::set<hwc2_layer_t>* outClearLayers = nullptr,
- bool* outFlipClientTarget = nullptr)
- {
- hwc2_display_request_t displayRequest =
- static_cast<hwc2_display_request_t>(0);
- std::vector<hwc2_layer_t> requestedLayers;
- std::vector<hwc2_layer_request_t> requests;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequest,
- &requestedLayers, &requests));
-
- EXPECT_EQ(numRequests, requests.size()) << "validate returned "
- << numRequests << " requests and get display requests returned "
- << requests.size() << " requests";
-
- for (size_t i = 0; i < requests.size(); i++) {
- hwc2_layer_t requestedLayer = requestedLayers.at(i);
- hwc2_layer_request_t request = requests.at(i);
-
- EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer),
- 1) << "get display requests returned an unknown layer";
- EXPECT_NE(request, 0) << "returned empty request for layer "
- << requestedLayer;
-
- if (outClearLayers && request
- == HWC2_LAYER_REQUEST_CLEAR_CLIENT_TARGET)
- outClearLayers->insert(requestedLayer);
- }
-
- if (outFlipClientTarget)
- *outFlipClientTarget = displayRequest
- & HWC2_DISPLAY_REQUEST_FLIP_CLIENT_TARGET;
- }
-
- void getChangedCompositionTypes(hwc2_display_t display,
- std::vector<hwc2_layer_t>* outLayers,
- std::vector<hwc2_composition_t>* outTypes,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
- getFunction(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t numElements = 0;
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numElements, nullptr, nullptr));
-
- if (err == HWC2_ERROR_NONE && numElements > 0) {
- outLayers->resize(numElements);
- outTypes->resize(numElements);
-
- err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numElements, reinterpret_cast<uint64_t*>(outLayers->data()),
- reinterpret_cast<int32_t*>(outTypes->data())));
- }
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get changed"
- " composition types";
- }
- }
-
- void handleCompositionChanges(hwc2_display_t display,
- const Hwc2TestLayers& testLayers,
- const std::vector<hwc2_layer_t>& layers, uint32_t numTypes,
- std::set<hwc2_layer_t>* outClientLayers = nullptr)
- {
- std::vector<hwc2_layer_t> changedLayers;
- std::vector<hwc2_composition_t> types;
-
- ASSERT_NO_FATAL_FAILURE(getChangedCompositionTypes(display,
- &changedLayers, &types));
-
- EXPECT_EQ(numTypes, types.size()) << "validate returned "
- << numTypes << " types and get changed composition types"
- " returned " << types.size() << " types";
-
- for (size_t i = 0; i < types.size(); i++) {
-
- auto layer = std::find(layers.begin(), layers.end(),
- changedLayers.at(i));
-
- EXPECT_TRUE(layer != layers.end() || !testLayers.contains(*layer))
- << "get changed composition types returned an unknown layer";
-
- hwc2_composition_t requestedType = testLayers.getComposition(*layer);
- hwc2_composition_t returnedType = types.at(i);
-
- EXPECT_NE(returnedType, HWC2_COMPOSITION_INVALID) << "get changed"
- " composition types returned invalid composition";
-
- switch (requestedType) {
- case HWC2_COMPOSITION_CLIENT:
- EXPECT_TRUE(false) << getCompositionName(returnedType)
- << " cannot be changed";
- break;
- case HWC2_COMPOSITION_DEVICE:
- case HWC2_COMPOSITION_SOLID_COLOR:
- EXPECT_EQ(returnedType, HWC2_COMPOSITION_CLIENT)
- << "composition of type "
- << getCompositionName(requestedType)
- << " can only be changed to "
- << getCompositionName(HWC2_COMPOSITION_CLIENT);
- break;
- case HWC2_COMPOSITION_CURSOR:
- case HWC2_COMPOSITION_SIDEBAND:
- EXPECT_TRUE(returnedType == HWC2_COMPOSITION_CLIENT
- || returnedType == HWC2_COMPOSITION_DEVICE)
- << "composition of type "
- << getCompositionName(requestedType)
- << " can only be changed to "
- << getCompositionName(HWC2_COMPOSITION_CLIENT) << " or "
- << getCompositionName(HWC2_COMPOSITION_DEVICE);
- break;
- default:
- EXPECT_TRUE(false) << "unknown type "
- << getCompositionName(requestedType);
- break;
- }
-
- if (outClientLayers)
- if (returnedType == HWC2_COMPOSITION_CLIENT)
- outClientLayers->insert(*layer);
- }
-
- if (outClientLayers) {
- for (auto layer : layers) {
- if (testLayers.getComposition(layer) == HWC2_COMPOSITION_CLIENT)
- outClientLayers->insert(layer);
- }
- }
- }
-
- void acceptDisplayChanges(hwc2_display_t display,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
- getFunction(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to accept display changes";
- }
- }
-
- void getClientTargetSupport(hwc2_display_t display, int32_t width,
- int32_t height, android_pixel_format_t format,
- Dataspace dataspace, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
- getFunction(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, width,
- height, format, static_cast<int>(dataspace)));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get client target"
- " support";
- }
- }
-
- void setClientTarget(hwc2_display_t display, buffer_handle_t handle,
- int32_t acquireFence, Dataspace dataspace,
- hwc_region_t damage, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_CLIENT_TARGET>(
- getFunction(HWC2_FUNCTION_SET_CLIENT_TARGET));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, handle,
- acquireFence, static_cast<int>(dataspace), damage));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set client target";
- }
- }
-
- void presentDisplay(hwc2_display_t display, int32_t* outPresentFence,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_PRESENT_DISPLAY>(
- getFunction(HWC2_FUNCTION_PRESENT_DISPLAY));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- outPresentFence));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to present display";
- }
- }
-
- void getReleaseFences(hwc2_display_t display,
- std::vector<hwc2_layer_t>* outLayers,
- std::vector<int32_t>* outFences, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_RELEASE_FENCES>(
- getFunction(HWC2_FUNCTION_GET_RELEASE_FENCES));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t numElements = 0;
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numElements, nullptr, nullptr));
-
- if (err == HWC2_ERROR_NONE) {
- outLayers->resize(numElements);
- outFences->resize(numElements);
-
- err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numElements, outLayers->data(), outFences->data()));
- }
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get release fences";
- }
- }
-
- void getColorModes(hwc2_display_t display,
- std::vector<ColorMode>* outColorModes,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_COLOR_MODES>(
- getFunction(HWC2_FUNCTION_GET_COLOR_MODES));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t numColorModes = 0;
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numColorModes, nullptr));
- if (err == HWC2_ERROR_NONE) {
- outColorModes->resize(numColorModes);
-
- err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numColorModes,
- reinterpret_cast<int32_t*>(outColorModes->data())));
- }
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get color modes for"
- " display " << display;
- }
- }
-
- void setColorMode(hwc2_display_t display, ColorMode colorMode,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_MODE>(
- getFunction(HWC2_FUNCTION_SET_COLOR_MODE));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- static_cast<int32_t>(colorMode)));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color mode "
- << static_cast<int>(colorMode);
- }
- }
-
- void getHdrCapabilities(hwc2_display_t display,
- std::vector<android_hdr_t>* outTypes, float* outMaxLuminance,
- float* outMaxAverageLuminance, float* outMinLuminance,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_HDR_CAPABILITIES>(
- getFunction(HWC2_FUNCTION_GET_HDR_CAPABILITIES));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t numTypes = 0;
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- &numTypes, nullptr, outMaxLuminance, outMaxAverageLuminance,
- outMinLuminance));
-
- if (err == HWC2_ERROR_NONE) {
- outTypes->resize(numTypes);
-
- err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &numTypes,
- reinterpret_cast<int32_t*>(outTypes->data()), outMaxLuminance,
- outMaxAverageLuminance, outMinLuminance));
- }
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get hdr capabilities"
- " for display " << display;
- }
- }
-
- void setColorTransform(hwc2_display_t display,
- const std::array<float, 16>& matrix, android_color_transform_t hint,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_TRANSFORM>(
- getFunction(HWC2_FUNCTION_SET_COLOR_TRANSFORM));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
- matrix.data(), hint));
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color transform "
- << hint;
- }
- }
-
- void createVirtualDisplay(uint32_t width, uint32_t height,
- android_pixel_format_t* outFormat, hwc2_display_t* outDisplay,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
- getFunction(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, width, height,
- reinterpret_cast<int32_t*>(outFormat), outDisplay));
-
- if (err == HWC2_ERROR_NONE)
- mVirtualDisplays.insert(*outDisplay);
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create virtual display";
- }
- }
-
- void destroyVirtualDisplay(hwc2_display_t display,
- hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
- getFunction(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display));
-
- if (err == HWC2_ERROR_NONE)
- mVirtualDisplays.erase(display);
-
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy virtual display";
- }
- }
-
- void getMaxVirtualDisplayCount(uint32_t* outMaxCnt)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
- getFunction(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- *outMaxCnt = pfn(mHwc2Device);
- }
-
- void setOutputBuffer(hwc2_display_t display, buffer_handle_t buffer,
- int32_t releaseFence, hwc2_error_t* outErr = nullptr)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_SET_OUTPUT_BUFFER>(
- getFunction(HWC2_FUNCTION_SET_OUTPUT_BUFFER));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, buffer,
- releaseFence));
- if (outErr) {
- *outErr = err;
- } else {
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set output buffer";
- }
- }
-
- void dump(std::string* outBuffer)
- {
- auto pfn = reinterpret_cast<HWC2_PFN_DUMP>(
- getFunction(HWC2_FUNCTION_DUMP));
- ASSERT_TRUE(pfn) << "failed to get function";
-
- uint32_t size = 0;
-
- pfn(mHwc2Device, &size, nullptr);
-
- std::vector<char> buffer(size);
-
- pfn(mHwc2Device, &size, buffer.data());
-
- outBuffer->assign(buffer.data());
- }
-
- void getBadDisplay(hwc2_display_t* outDisplay)
- {
- for (hwc2_display_t display = 0; display < UINT64_MAX; display++) {
- if (mDisplays.count(display) == 0) {
- *outDisplay = display;
- return;
- }
- }
- ASSERT_TRUE(false) << "Unable to find bad display. UINT64_MAX displays"
- " are registered. This should never happen.";
- }
-
- void waitForVsync(hwc2_display_t* outDisplay = nullptr,
- int64_t* outTimestamp = nullptr)
- {
- std::unique_lock<std::mutex> lock(mVsyncMutex);
- ASSERT_EQ(mVsyncCv.wait_for(lock, std::chrono::seconds(3)),
- std::cv_status::no_timeout) << "timed out attempting to get"
- " vsync callback";
- if (outDisplay)
- *outDisplay = mVsyncDisplay;
- if (outTimestamp)
- *outTimestamp = mVsyncTimestamp;
- }
-
- void enableVsync(hwc2_display_t display)
- {
- ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, this,
- reinterpret_cast<hwc2_function_pointer_t>(
- hwc2TestVsyncCallback)));
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
- }
-
- void disableVsync(hwc2_display_t display)
- {
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
- }
-
-protected:
- hwc2_function_pointer_t getFunction(hwc2_function_descriptor_t descriptor)
- {
- return mHwc2Device->getFunction(mHwc2Device, descriptor);
- }
-
- void getCapabilities(std::vector<hwc2_capability_t>* outCapabilities)
- {
- uint32_t num = 0;
-
- mHwc2Device->getCapabilities(mHwc2Device, &num, nullptr);
-
- outCapabilities->resize(num);
-
- mHwc2Device->getCapabilities(mHwc2Device, &num,
- reinterpret_cast<int32_t*>(outCapabilities->data()));
- }
-
- /* Registers a hotplug callback and waits for hotplug callbacks. This
- * function will have no effect if called more than once. */
- void populateDisplays()
- {
- /* Sets the hotplug status to receiving */
- {
- std::lock_guard<std::mutex> lock(mHotplugMutex);
-
- if (mHotplugStatus != Hwc2TestHotplugStatus::Init)
- return;
- mHotplugStatus = Hwc2TestHotplugStatus::Receiving;
- }
-
- /* Registers the callback. This function call cannot be locked because
- * a callback could happen on the same thread */
- ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_HOTPLUG, this,
- reinterpret_cast<hwc2_function_pointer_t>(
- hwc2TestHotplugCallback)));
-
- /* Waits for hotplug events. If a hotplug event has not come within 1
- * second, stop waiting. */
- std::unique_lock<std::mutex> lock(mHotplugMutex);
-
- while (mHotplugCv.wait_for(lock, std::chrono::seconds(1)) !=
- std::cv_status::timeout) { }
-
- /* Sets the hotplug status to done. Future calls will have no effect */
- mHotplugStatus = Hwc2TestHotplugStatus::Done;
- }
-
- /* NOTE: will create min(newlayerCnt, max supported layers) layers */
- void createLayers(hwc2_display_t display,
- std::vector<hwc2_layer_t>* outLayers, size_t newLayerCnt)
- {
- std::vector<hwc2_layer_t> newLayers;
- hwc2_layer_t layer;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- for (size_t i = 0; i < newLayerCnt; i++) {
-
- EXPECT_NO_FATAL_FAILURE(createLayer(display, &layer, &err));
- if (err == HWC2_ERROR_NO_RESOURCES)
- break;
- if (err != HWC2_ERROR_NONE) {
- newLayers.clear();
- ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer";
- }
- newLayers.push_back(layer);
- }
-
- *outLayers = std::move(newLayers);
- }
-
- void destroyLayers(hwc2_display_t display,
- std::vector<hwc2_layer_t>&& layers)
- {
- for (hwc2_layer_t layer : layers) {
- EXPECT_NO_FATAL_FAILURE(destroyLayer(display, layer));
- }
- }
-
- void getInvalidConfig(hwc2_display_t display, hwc2_config_t* outConfig)
- {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- hwc2_config_t CONFIG_MAX = UINT32_MAX;
-
- ASSERT_LE(configs.size() - 1, CONFIG_MAX) << "every config value"
- " (2^32 values) has been taken which shouldn't happen";
-
- hwc2_config_t config;
- for (config = 0; config < CONFIG_MAX; config++) {
- if (std::count(configs.begin(), configs.end(), config) == 0)
- break;
- }
-
- *outConfig = config;
- }
-
- /* Calls a set property function from Hwc2Test to set a property value from
- * Hwc2TestLayer to hwc2_layer_t on hwc2_display_t */
- using TestLayerPropertyFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr);
-
- /* Calls a set property function from Hwc2Test to set property values from
- * Hwc2TestLayers to hwc2_layer_t on hwc2_display_t */
- using TestLayerPropertiesFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayers* testLayers);
-
- /* Calls a set property function from Hwc2Test to set a bad property value
- * on hwc2_layer_t on hwc2_display_t */
- using TestLayerPropertyBadLayerFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr);
-
- /* Calls a set property function from Hwc2Test to set a bad property value
- * on hwc2_layer_t on hwc2_display_t */
- using TestLayerPropertyBadParameterFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display, hwc2_layer_t layer, hwc2_error_t* outErr);
-
- /* Is called after a display is powered on and all layer properties have
- * been set. It should be used to test functions such as validate, accepting
- * changes, present, etc. */
- using TestDisplayLayersFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display, const std::vector<hwc2_layer_t>& layers,
- Hwc2TestLayers* testLayers);
-
- /* It is called on an non validated display */
- using TestDisplayNonValidatedLayersFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display, std::vector<hwc2_layer_t>* layers);
-
- /* Tests client target support on a particular display and config */
- using TestClientTargetSupportFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display,
- const Hwc2TestClientTargetSupport& testClientTargetSupport);
-
- /* Tests a particular active display config */
- using TestActiveDisplayConfigFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display);
-
- /* Tests a newly created virtual display */
- using TestCreateVirtualDisplayFunction = void (*)(Hwc2Test* test,
- hwc2_display_t display, Hwc2TestVirtualDisplay* testVirtualDisplay);
-
- /* Advances a property of Hwc2TestLayer */
- using AdvanceProperty = bool (*)(Hwc2TestLayer* testLayer);
-
- /* Advances properties of Hwc2TestLayers */
- using AdvanceProperties = bool (*)(Hwc2TestLayers* testLayer);
-
- /* Advances properties of Hwc2TestClientTargetSupport */
- using AdvanceClientTargetSupport = bool (*)(
- Hwc2TestClientTargetSupport* testClientTargetSupport);
-
- /* For each active display it cycles through each display config and tests
- * each property value. It creates a layer, sets the property and then
- * destroys the layer */
- void setLayerProperty(Hwc2TestCoverage coverage,
- TestLayerPropertyFunction function, AdvanceProperty advance)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- hwc2_layer_t layer;
- Area displayArea;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
- &displayArea));
- Hwc2TestLayer testLayer(coverage, displayArea);
-
- do {
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
- &testLayer, nullptr));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
- } while (advance(&testLayer));
- }
- }
- }
-
- /* For each active display it cycles through each display config and tests
- * each property value. It creates a layer, cycles through each property
- * value and updates the layer property value and then destroys the layer */
- void setLayerPropertyUpdate(Hwc2TestCoverage coverage,
- TestLayerPropertyFunction function, AdvanceProperty advance)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- hwc2_layer_t layer;
- Area displayArea;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
- &displayArea));
- Hwc2TestLayer testLayer(coverage, displayArea);
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- do {
- ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
- &testLayer, nullptr));
- } while (advance(&testLayer));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
- }
- }
- }
-
- /* For each active display it cycles through each display config and tests
- * each property value. It creates multiple layers, calls the
- * TestLayerPropertiesFunction to set property values and then
- * destroys the layers */
- void setLayerProperties(Hwc2TestCoverage coverage, size_t layerCnt,
- TestLayerPropertiesFunction function, AdvanceProperties advance)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- std::vector<hwc2_layer_t> layers;
- Area displayArea;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
- &displayArea));
-
- ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
- Hwc2TestLayers testLayers(layers, coverage, displayArea);
-
- do {
- for (auto layer : layers) {
- EXPECT_NO_FATAL_FAILURE(function(this, display, layer,
- &testLayers));
- }
- } while (advance(&testLayers));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
- }
- }
- }
-
- /* For each active display it cycles through each display config.
- * 1) It attempts to set a valid property value to bad layer handle.
- * 2) It creates a layer x and attempts to set a valid property value to
- * layer x + 1
- * 3) It destroys the layer x and attempts to set a valid property value to
- * the destroyed layer x.
- */
- void setLayerPropertyBadLayer(Hwc2TestCoverage coverage,
- TestLayerPropertyBadLayerFunction function)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- hwc2_layer_t layer = 0;
- Area displayArea;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
- &displayArea));
- Hwc2TestLayer testLayer(coverage, displayArea);
-
- ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
- &testLayer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- ASSERT_NO_FATAL_FAILURE(function(this, display, layer + 1,
- &testLayer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-
- ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
- &testLayer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
- }
- }
- }
-
- /* For each active display it cycles through each display config and tests
- * each property value. It creates a layer, sets a bad property value and
- * then destroys the layer */
- void setLayerPropertyBadParameter(TestLayerPropertyBadParameterFunction function)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- hwc2_layer_t layer;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- ASSERT_NO_FATAL_FAILURE(function(this, display, layer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong"
- " error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
- }
- }
- }
-
- /* For each active display it powers on the display, cycles through each
- * config and creates a set of layers with a certain amount of coverage.
- * For each active display, for each config and for each set of layers,
- * it calls the TestDisplayLayersFunction */
- void displayLayers(Hwc2TestCoverage coverage, size_t layerCnt,
- TestDisplayLayersFunction function)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- Area displayArea;
- std::vector<hwc2_layer_t> layers;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea));
-
- ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
- Hwc2TestLayers testLayers(layers, coverage, displayArea);
-
- do {
- bool skip;
-
- ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
- &testLayers, &skip));
- if (!skip)
- EXPECT_NO_FATAL_FAILURE(function(this, display, layers,
- &testLayers));
-
- } while (testLayers.advance());
-
- ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
- std::move(layers)));
- }
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
- }
-
- /* For each active display, it calls the
- * TestDisplayNonValidatedLayersFunction on a variety on non-validated
- * layer combinations */
- void displayNonValidatedLayers(size_t layerCnt,
- TestDisplayNonValidatedLayersFunction function)
- {
- for (auto display : mDisplays) {
- uint32_t numTypes, numRequests;
- std::vector<hwc2_layer_t> layers;
- bool hasChanges;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
- ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-
- EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
- for (auto layer : layers) {
- ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
- HWC2_COMPOSITION_CLIENT));
- }
-
- EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
- ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
-
- for (auto layer : layers) {
- ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
- HWC2_COMPOSITION_DEVICE));
- }
-
- EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
-
- EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
- }
-
- /* Test client target support on each config on each active display */
- void setClientTargetSupport(Hwc2TestCoverage coverage,
- TestClientTargetSupportFunction function,
- AdvanceClientTargetSupport advance)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- Area displayArea;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
- &displayArea));
- Hwc2TestClientTargetSupport testClientTargetSupport(coverage,
- displayArea);
-
- do {
- EXPECT_NO_FATAL_FAILURE(function(this, display,
- testClientTargetSupport));
-
- } while (advance(&testClientTargetSupport));
- }
- }
- }
-
- /* Cycles through each config on each active display and calls
- * a TestActiveDisplayConfigFunction */
- void setActiveDisplayConfig(TestActiveDisplayConfigFunction function)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
- EXPECT_NO_FATAL_FAILURE(function(this, display));
- }
- }
- }
-
- /* Creates a virtual display for testing */
- void createVirtualDisplay(Hwc2TestCoverage coverage,
- TestCreateVirtualDisplayFunction function)
- {
- Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
-
- do {
- hwc2_display_t display;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- const UnsignedArea& dimension =
- testVirtualDisplay.getDisplayDimension();
- android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
- dimension.height, &desiredFormat, &display, &err));
-
- EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES
- || err == HWC2_ERROR_UNSUPPORTED)
- << "returned wrong error code";
- EXPECT_GE(desiredFormat, 0) << "invalid format";
-
- if (err != HWC2_ERROR_NONE)
- continue;
-
- EXPECT_NO_FATAL_FAILURE(function(this, display,
- &testVirtualDisplay));
-
- ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
-
- } while (testVirtualDisplay.advance());
- }
-
-
- void getActiveConfigAttribute(hwc2_display_t display,
- hwc2_attribute_t attribute, int32_t* outValue)
- {
- hwc2_config_t config;
- ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &config));
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
- attribute, outValue));
- ASSERT_GE(*outValue, 0) << "failed to get valid "
- << getAttributeName(attribute);
- }
-
- void getActiveDisplayArea(hwc2_display_t display, Area* displayArea)
- {
- ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display,
- HWC2_ATTRIBUTE_WIDTH, &displayArea->width));
- ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display,
- HWC2_ATTRIBUTE_HEIGHT, &displayArea->height));
- }
-
- void closeFences(hwc2_display_t display, int32_t presentFence)
- {
- std::vector<hwc2_layer_t> layers;
- std::vector<int32_t> fences;
- const int msWait = 3000;
-
- if (presentFence >= 0) {
- ASSERT_GE(sync_wait(presentFence, msWait), 0);
- close(presentFence);
- }
-
- ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences));
- EXPECT_EQ(layers.size(), fences.size());
-
- for (int32_t fence : fences) {
- if (fence >= 0) {
- EXPECT_GE(sync_wait(fence, msWait), 0);
- close(fence);
- }
- }
- }
-
- void setLayerProperties(hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayers* testLayers, bool* outSkip)
- {
- hwc2_composition_t composition;
- buffer_handle_t handle = nullptr;
- int32_t acquireFence;
- hwc2_error_t err = HWC2_ERROR_NONE;
- *outSkip = true;
-
- if (!testLayers->contains(layer))
- return;
-
- composition = testLayers->getComposition(layer);
-
- /* If the device cannot support a buffer format, then do not continue */
- if ((composition == HWC2_COMPOSITION_DEVICE
- || composition == HWC2_COMPOSITION_CURSOR)
- && testLayers->getBuffer(layer, &handle, &acquireFence) < 0)
- return;
-
- EXPECT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
- composition, &err));
- if (err == HWC2_ERROR_UNSUPPORTED)
- EXPECT_TRUE(composition != HWC2_COMPOSITION_CLIENT
- && composition != HWC2_COMPOSITION_DEVICE);
-
- const hwc_rect_t cursor = testLayers->getCursorPosition(layer);
-
- EXPECT_NO_FATAL_FAILURE(setLayerBuffer(display, layer, handle,
- acquireFence));
- EXPECT_NO_FATAL_FAILURE(setLayerBlendMode(display, layer,
- testLayers->getBlendMode(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer,
- testLayers->getColor(layer)));
- if (composition == HWC2_COMPOSITION_CURSOR)
- EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer,
- cursor.left, cursor.top));
- EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer,
- testLayers->getDataspace(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer,
- testLayers->getDisplayFrame(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerPlaneAlpha(display, layer,
- testLayers->getPlaneAlpha(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerSourceCrop(display, layer,
- testLayers->getSourceCrop(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerSurfaceDamage(display, layer,
- testLayers->getSurfaceDamage(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerTransform(display, layer,
- testLayers->getTransform(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerVisibleRegion(display, layer,
- testLayers->getVisibleRegion(layer)));
- EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer,
- testLayers->getZOrder(layer)));
-
- *outSkip = false;
- }
-
- void setLayerProperties(hwc2_display_t display,
- const std::vector<hwc2_layer_t>& layers,
- Hwc2TestLayers* testLayers, bool* outSkip)
- {
- for (auto layer : layers) {
- EXPECT_NO_FATAL_FAILURE(setLayerProperties(display, layer,
- testLayers, outSkip));
- if (*outSkip)
- return;
- }
- }
-
- void setClientTarget(hwc2_display_t display,
- Hwc2TestClientTarget* testClientTarget,
- const Hwc2TestLayers& testLayers,
- const std::set<hwc2_layer_t>& clientLayers,
- const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
- const Area& displayArea)
- {
- Dataspace dataspace = Dataspace::UNKNOWN;
- hwc_region_t damage = { };
- buffer_handle_t handle;
- int32_t acquireFence;
-
- ASSERT_EQ(testClientTarget->getBuffer(testLayers, clientLayers,
- clearLayers, flipClientTarget, displayArea, &handle,
- &acquireFence), 0);
- EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence,
- dataspace, damage));
- }
-
- void presentDisplays(size_t layerCnt, Hwc2TestCoverage coverage,
- const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
- coverageExceptions, bool optimize)
- {
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
- ASSERT_NO_FATAL_FAILURE(enableVsync(display));
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- Area displayArea;
- std::vector<hwc2_layer_t> layers;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
- &displayArea));
-
- ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
- Hwc2TestLayers testLayers(layers, coverage, displayArea,
- coverageExceptions);
-
- if (optimize && !testLayers.optimizeLayouts())
- continue;
-
- std::set<hwc2_layer_t> clientLayers;
- std::set<hwc2_layer_t> clearLayers;
- Hwc2TestClientTarget testClientTarget;
-
- do {
- uint32_t numTypes, numRequests;
- bool hasChanges, skip;
- bool flipClientTarget;
- int32_t presentFence;
-
- ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
- &testLayers, &skip));
- if (skip)
- continue;
-
- ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
- if (hasChanges)
- EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
- << "wrong number of requests";
-
- ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
- testLayers, layers, numTypes, &clientLayers));
- ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
- numRequests, &clearLayers, &flipClientTarget));
- ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
- &testClientTarget, testLayers, clientLayers,
- clearLayers, flipClientTarget, displayArea));
- ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
-
- ASSERT_NO_FATAL_FAILURE(waitForVsync());
-
- EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
- &presentFence));
-
- ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
-
- } while (testLayers.advance());
-
- ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
- std::move(layers)));
- }
-
- ASSERT_NO_FATAL_FAILURE(disableVsync(display));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
- }
-
- void createAndPresentVirtualDisplay(size_t layerCnt,
- Hwc2TestCoverage coverage,
- const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
- coverageExceptions)
- {
- Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
- hwc2_display_t display;
- android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-
- do {
- // Items dependent on the display dimensions
- hwc2_error_t err = HWC2_ERROR_NONE;
- const UnsignedArea& dimension =
- testVirtualDisplay.getDisplayDimension();
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
- dimension.height, &desiredFormat, &display, &err));
- ASSERT_TRUE(err == HWC2_ERROR_NONE)
- << "Cannot allocate virtual display";
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
- ASSERT_NO_FATAL_FAILURE(enableVsync(display));
-
- std::vector<hwc2_config_t> configs;
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
- Area displayArea;
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
- &displayArea));
-
- std::vector<hwc2_layer_t> layers;
- ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers,
- layerCnt));
- Hwc2TestLayers testLayers(layers, coverage, displayArea,
- coverageExceptions);
-
- /*
- * Layouts that do not cover an entire virtual display will
- * cause undefined behavior.
- * Enable optimizeLayouts to avoid this.
- */
- testLayers.optimizeLayouts();
- do {
- // Items dependent on the testLayers properties
- std::set<hwc2_layer_t> clientLayers;
- std::set<hwc2_layer_t> clearLayers;
- uint32_t numTypes, numRequests;
- bool hasChanges, skip;
- bool flipClientTarget;
- int32_t presentFence;
- Hwc2TestClientTarget testClientTarget;
- buffer_handle_t outputBufferHandle;
- android::base::unique_fd outputBufferReleaseFence;
-
- ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
- &testLayers, &skip));
-
- if (skip)
- continue;
-
- ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
-
- if (hasChanges)
- EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
- << "wrong number of requests";
-
- ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
- testLayers, layers, numTypes, &clientLayers));
-
- ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
- numRequests, &clearLayers, &flipClientTarget));
- ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
- &testClientTarget, testLayers, clientLayers,
- clearLayers, flipClientTarget, displayArea));
- ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
-
- ASSERT_EQ(testVirtualDisplay.getOutputBuffer(
- &outputBufferHandle, &outputBufferReleaseFence), 0);
- ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display,
- outputBufferHandle, outputBufferReleaseFence));
-
- EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
- &presentFence));
- ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
-
- ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers,
- &layers, &clearLayers), 0);
-
- /*
- * Upscaling the image causes minor pixel differences.
- * Work around this by using some threshold.
- *
- * Fail test if we are off by more than 1% of our
- * pixels.
- */
- ComparatorResult& comparatorResult = ComparatorResult::get();
- int threshold = (dimension.width * dimension.height) / 100;
- double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) /
- (dimension.width * dimension.height);
-
- if (comparatorResult.getDifferentPixelCount() != 0)
- EXPECT_TRUE(false)
- << comparatorResult.getDifferentPixelCount() << " pixels ("
- << diffPercent << "%) are different.";
-
- if (comparatorResult.getDifferentPixelCount() > threshold) {
- EXPECT_TRUE(false)
- << "Mismatched pixel count exceeds threshold. "
- << "Writing buffers to file.";
-
- const ::testing::TestInfo* const test_info =
- ::testing::UnitTest::GetInstance()
- ->current_test_info();
-
- EXPECT_EQ(testVirtualDisplay.writeBuffersToFile(
- test_info->name()), 0)
- << "Failed to write buffers.";
- }
-
- ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold)
- << comparatorResult.getDifferentPixelCount() << " pixels ("
- << diffPercent << "%) are different. "
- << "Exceeds 1% threshold, terminating test. "
- << "Test case: " << testLayers.dump();
-
- } while (testLayers.advance());
-
- ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
- std::move(layers)));
- }
- ASSERT_NO_FATAL_FAILURE(disableVsync(display));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
- } while (testVirtualDisplay.advance());
- }
-
- hwc2_device_t* mHwc2Device = nullptr;
-
- enum class Hwc2TestHotplugStatus {
- Init = 1,
- Receiving,
- Done,
- };
-
- std::mutex mHotplugMutex;
- std::condition_variable mHotplugCv;
- Hwc2TestHotplugStatus mHotplugStatus = Hwc2TestHotplugStatus::Init;
- std::unordered_set<hwc2_display_t> mDisplays;
-
- /* Store all created layers that have not been destroyed. If an ASSERT_*
- * fails, then destroy the layers on exit */
- std::set<std::pair<hwc2_display_t, hwc2_layer_t>> mLayers;
-
- /* Store the power mode state. If it is not HWC2_POWER_MODE_OFF when
- * tearing down the test cases, change it to HWC2_POWER_MODE_OFF */
- std::set<hwc2_display_t> mActiveDisplays;
-
- /* Store all created virtual displays that have not been destroyed. If an
- * ASSERT_* fails, then destroy the virtual displays on exit */
- std::set<hwc2_display_t> mVirtualDisplays;
-
- std::mutex mVsyncMutex;
- std::condition_variable mVsyncCv;
- hwc2_display_t mVsyncDisplay;
- int64_t mVsyncTimestamp = -1;
-};
-
-void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int32_t connection)
-{
- if (callbackData)
- static_cast<Hwc2Test*>(callbackData)->hotplugCallback(display,
- connection);
-}
-
-void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
- hwc2_display_t display, int64_t timestamp)
-{
- if (callbackData)
- static_cast<Hwc2Test*>(callbackData)->vsyncCallback(display,
- timestamp);
-}
-
-void setBlendMode(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer,
- testLayer->getBlendMode(), outErr));
-}
-
-void setBuffer(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- buffer_handle_t handle;
- android::base::unique_fd acquireFence;
- hwc2_composition_t composition = testLayer->getComposition();
-
- if (composition == HWC2_COMPOSITION_CLIENT
- || composition == HWC2_COMPOSITION_SOLID_COLOR
- || composition == HWC2_COMPOSITION_SIDEBAND)
- return;
-
- if (testLayer->getBuffer(&handle, &acquireFence) < 0)
- return;
-
- ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer,
- composition));
- EXPECT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer,
- handle, acquireFence, outErr));
-}
-
-void setColor(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
- layer, HWC2_COMPOSITION_SOLID_COLOR));
- ASSERT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display,
- layer, testLayer->getPlaneAlpha()));
- ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display,
- layer, testLayer->getBlendMode()));
- EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer,
- testLayer->getColor(), outErr));
-}
-
-void setComposition(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- hwc2_composition_t composition = testLayer->getComposition();
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer,
- composition, &err));
- if (outErr) {
- *outErr = err;
- return;
- }
-
- if (composition != HWC2_COMPOSITION_SIDEBAND) {
- EXPECT_EQ(err, HWC2_ERROR_NONE) << "returned wrong error code";
- } else {
- EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED)
- << "returned wrong error code";
- }
-}
-
-void setCursorPosition(Hwc2Test* test, hwc2_display_t display,
- hwc2_layer_t layer, Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
- layer, HWC2_COMPOSITION_CURSOR));
-
- const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
- EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
- cursorPosition.left, cursorPosition.top, outErr));
-}
-
-void setDataspace(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerDataspace(display, layer,
- testLayer->getDataspace(), outErr));
-}
-
-void setDisplayFrame(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerDisplayFrame(display, layer,
- testLayer->getDisplayFrame(), outErr));
-}
-
-void setPlaneAlpha(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t *outErr)
-{
- ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer,
- testLayer->getBlendMode()));
- EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, layer,
- testLayer->getPlaneAlpha(), outErr));
-}
-
-void setSourceCrop(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerSourceCrop(display, layer,
- testLayer->getSourceCrop(), outErr));
-}
-
-void setSurfaceDamage(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerSurfaceDamage(display, layer,
- testLayer->getSurfaceDamage(), outErr));
-}
-
-void setTransform(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerTransform(display, layer,
- testLayer->getTransform(), outErr));
-}
-
-void setVisibleRegion(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display, layer,
- testLayer->getVisibleRegion(), outErr));
-}
-
-void setZOrder(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
- EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer,
- testLayer->getZOrder(), outErr));
-}
-
-bool advanceBlendMode(Hwc2TestLayer* testLayer)
-{
- return testLayer->advanceBlendMode();
-}
-
-bool advanceBuffer(Hwc2TestLayer* testLayer)
-{
- if (testLayer->advanceComposition())
- return true;
- return testLayer->advanceBufferArea();
-}
-
-bool advanceColor(Hwc2TestLayer* testLayer)
-{
- /* Color depends on blend mode so advance blend mode last so color is not
- * force to update as often */
- if (testLayer->advancePlaneAlpha())
- return true;
- if (testLayer->advanceColor())
- return true;
- return testLayer->advanceBlendMode();
-}
-
-bool advanceComposition(Hwc2TestLayer* testLayer)
-{
- return testLayer->advanceComposition();
-}
-
-bool advanceCursorPosition(Hwc2TestLayer* testLayer)
-{
- return testLayer->advanceCursorPosition();
-}
-
-bool advanceDataspace(Hwc2TestLayer* testLayer)
-{
- return testLayer->advanceDataspace();
-}
-
-bool advanceDisplayFrame(Hwc2TestLayer* testLayer)
-{
- return testLayer->advanceDisplayFrame();
-}
-
-bool advancePlaneAlpha(Hwc2TestLayer* testLayer)
-{
- return testLayer->advancePlaneAlpha();
-}
-
-bool advanceSourceCrop(Hwc2TestLayer* testLayer)
-{
- if (testLayer->advanceSourceCrop())
- return true;
- return testLayer->advanceBufferArea();
-}
-
-bool advanceSurfaceDamage(Hwc2TestLayer* testLayer)
-{
- if (testLayer->advanceSurfaceDamage())
- return true;
- return testLayer->advanceBufferArea();
-}
-
-bool advanceTransform(Hwc2TestLayer* testLayer)
-{
- return testLayer->advanceTransform();
-}
-
-bool advanceVisibleRegions(Hwc2TestLayers* testLayers)
-{
- return testLayers->advanceVisibleRegions();
-}
-
-bool advanceClientTargetSupport(
- Hwc2TestClientTargetSupport* testClientTargetSupport)
-{
- return testClientTargetSupport->advance();
-}
-
-static const std::array<hwc2_function_descriptor_t, 42> requiredFunctions = {{
- HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES,
- HWC2_FUNCTION_CREATE_LAYER,
- HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY,
- HWC2_FUNCTION_DESTROY_LAYER,
- HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY,
- HWC2_FUNCTION_DUMP,
- HWC2_FUNCTION_GET_ACTIVE_CONFIG,
- HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES,
- HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT,
- HWC2_FUNCTION_GET_COLOR_MODES,
- HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE,
- HWC2_FUNCTION_GET_DISPLAY_CONFIGS,
- HWC2_FUNCTION_GET_DISPLAY_NAME,
- HWC2_FUNCTION_GET_DISPLAY_REQUESTS,
- HWC2_FUNCTION_GET_DISPLAY_TYPE,
- HWC2_FUNCTION_GET_DOZE_SUPPORT,
- HWC2_FUNCTION_GET_HDR_CAPABILITIES,
- HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT,
- HWC2_FUNCTION_GET_RELEASE_FENCES,
- HWC2_FUNCTION_PRESENT_DISPLAY,
- HWC2_FUNCTION_REGISTER_CALLBACK,
- HWC2_FUNCTION_SET_ACTIVE_CONFIG,
- HWC2_FUNCTION_SET_CLIENT_TARGET,
- HWC2_FUNCTION_SET_COLOR_MODE,
- HWC2_FUNCTION_SET_COLOR_TRANSFORM,
- HWC2_FUNCTION_SET_CURSOR_POSITION,
- HWC2_FUNCTION_SET_LAYER_BLEND_MODE,
- HWC2_FUNCTION_SET_LAYER_BUFFER,
- HWC2_FUNCTION_SET_LAYER_COLOR,
- HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE,
- HWC2_FUNCTION_SET_LAYER_DATASPACE,
- HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME,
- HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA,
- HWC2_FUNCTION_SET_LAYER_SOURCE_CROP,
- HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE,
- HWC2_FUNCTION_SET_LAYER_TRANSFORM,
- HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION,
- HWC2_FUNCTION_SET_LAYER_Z_ORDER,
- HWC2_FUNCTION_SET_OUTPUT_BUFFER,
- HWC2_FUNCTION_SET_POWER_MODE,
- HWC2_FUNCTION_SET_VSYNC_ENABLED,
- HWC2_FUNCTION_VALIDATE_DISPLAY,
-}};
-
-/* TESTCASE: Tests that the HWC2 supports all required functions. */
-TEST_F(Hwc2Test, GET_FUNCTION)
-{
- for (hwc2_function_descriptor_t descriptor : requiredFunctions) {
- hwc2_function_pointer_t pfn = getFunction(descriptor);
- EXPECT_TRUE(pfn) << "failed to get function "
- << getFunctionDescriptorName(descriptor);
- }
-}
-
-/* TESTCASE: Tests that the HWC2 fails to retrieve and invalid function. */
-TEST_F(Hwc2Test, GET_FUNCTION_invalid_function)
-{
- hwc2_function_pointer_t pfn = getFunction(HWC2_FUNCTION_INVALID);
- EXPECT_FALSE(pfn) << "failed to get invalid function";
-}
-
-/* TESTCASE: Tests that the HWC2 does not return an invalid capability. */
-TEST_F(Hwc2Test, GET_CAPABILITIES)
-{
- std::vector<hwc2_capability_t> capabilities;
-
- getCapabilities(&capabilities);
-
- EXPECT_EQ(std::count(capabilities.begin(), capabilities.end(),
- HWC2_CAPABILITY_INVALID), 0);
-}
-
-static const std::array<hwc2_callback_descriptor_t, 3> callbackDescriptors = {{
- HWC2_CALLBACK_HOTPLUG,
- HWC2_CALLBACK_REFRESH,
- HWC2_CALLBACK_VSYNC,
-}};
-
-/* TESTCASE: Tests that the HWC2 can successfully register all required
- * callback functions. */
-TEST_F(Hwc2Test, REGISTER_CALLBACK)
-{
- hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
- const_cast<char*>("data"));
-
- for (auto descriptor : callbackDescriptors) {
- ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data,
- []() { return; }));
- }
-}
-
-/* TESTCASE: Test that the HWC2 fails to register invalid callbacks. */
-TEST_F(Hwc2Test, REGISTER_CALLBACK_bad_parameter)
-{
- hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
- const_cast<char*>("data"));
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_INVALID, data,
- []() { return; }, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can register a callback with null data. */
-TEST_F(Hwc2Test, REGISTER_CALLBACK_null_data)
-{
- hwc2_callback_data_t data = nullptr;
-
- for (auto descriptor : callbackDescriptors) {
- ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data,
- []() { return; }));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 returns the correct display type for each
- * physical display. */
-TEST_F(Hwc2Test, GET_DISPLAY_TYPE)
-{
- for (auto display : mDisplays) {
- hwc2_display_type_t type;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type));
- EXPECT_EQ(type, HWC2_DISPLAY_TYPE_PHYSICAL) << "failed to return"
- " correct display type";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 returns an error when the display type of a bad
- * display is requested. */
-TEST_F(Hwc2Test, GET_DISPLAY_TYPE_bad_display)
-{
- hwc2_display_t display;
- hwc2_display_type_t type;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can create and destroy layers. */
-TEST_F(Hwc2Test, CREATE_DESTROY_LAYER)
-{
- for (auto display : mDisplays) {
- hwc2_layer_t layer;
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot create a layer for a bad display */
-TEST_F(Hwc2Test, CREATE_LAYER_bad_display)
-{
- hwc2_display_t display;
- hwc2_layer_t layer;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 will either support a large number of resources
- * or will return no resources. */
-TEST_F(Hwc2Test, CREATE_LAYER_no_resources)
-{
- const size_t layerCnt = 1000;
-
- for (auto display : mDisplays) {
- std::vector<hwc2_layer_t> layers;
-
- ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destroy a layer for a bad display */
-TEST_F(Hwc2Test, DESTROY_LAYER_bad_display)
-{
- hwc2_display_t badDisplay;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&badDisplay));
-
- for (auto display : mDisplays) {
- hwc2_layer_t layer = 0;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destory a bad layer */
-TEST_F(Hwc2Test, DESTROY_LAYER_bad_layer)
-{
- for (auto display : mDisplays) {
- hwc2_layer_t layer;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX / 2, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 0, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX - 1, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 1, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer + 1, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
- }
-}
-
-static const std::array<hwc2_attribute_t, 2> requiredAttributes = {{
- HWC2_ATTRIBUTE_WIDTH,
- HWC2_ATTRIBUTE_HEIGHT,
-}};
-
-static const std::array<hwc2_attribute_t, 3> optionalAttributes = {{
- HWC2_ATTRIBUTE_VSYNC_PERIOD,
- HWC2_ATTRIBUTE_DPI_X,
- HWC2_ATTRIBUTE_DPI_Y,
-}};
-
-/* TESTCASE: Tests that the HWC2 can return display attributes for a valid
- * config. */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE)
-{
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- int32_t value;
-
- for (auto attribute : requiredAttributes) {
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
- attribute, &value));
- EXPECT_GE(value, 0) << "missing required attribute "
- << getAttributeName(attribute) << " for config "
- << config;
- }
- for (auto attribute : optionalAttributes) {
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
- attribute, &value));
- }
- }
- }
-}
-
-/* TESTCASE: Tests that the HWC2 will return a value of -1 for an invalid
- * attribute */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_invalid_attribute)
-{
- const hwc2_attribute_t attribute = HWC2_ATTRIBUTE_INVALID;
-
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- int32_t value;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
- attribute, &value, &err));
- EXPECT_EQ(value, -1) << "failed to return -1 for an invalid"
- " attribute for config " << config;
- }
- }
-}
-
-/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad display */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_display)
-{
- hwc2_display_t display;
- const hwc2_config_t config = 0;
- int32_t value;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- for (auto attribute : requiredAttributes) {
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute,
- &value, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
- }
-
- for (auto attribute : optionalAttributes) {
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute,
- &value, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad config */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_config)
-{
- for (auto display : mDisplays) {
- hwc2_config_t config;
- int32_t value;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config));
-
- for (auto attribute : requiredAttributes) {
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
- attribute, &value, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
- }
-
- for (auto attribute : optionalAttributes) {
- ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
- attribute, &value, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
- }
- }
-}
-
-/* TESTCASE: Tests that the HWC2 will get display configs for active displays */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS)
-{
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 will not get display configs for bad displays */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_bad_display)
-{
- hwc2_display_t display;
- std::vector<hwc2_config_t> configs;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs, &err));
-
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
- EXPECT_TRUE(configs.empty()) << "returned configs for bad display";
-}
-
-/* TESTCASE: Tests that the HWC2 will return the same config list multiple
- * times in a row. */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_same)
-{
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs1, configs2;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs1));
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs2));
-
- EXPECT_TRUE(std::is_permutation(configs1.begin(), configs1.end(),
- configs2.begin())) << "returned two different config sets";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 does not return duplicate display configs */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_duplicate)
-{
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- std::unordered_set<hwc2_config_t> configsSet(configs.begin(),
- configs.end());
- EXPECT_EQ(configs.size(), configsSet.size()) << "returned duplicate"
- " configs";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 returns the active config for a display */
-TEST_F(Hwc2Test, GET_ACTIVE_CONFIG)
-{
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- hwc2_config_t activeConfig;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig));
-
- EXPECT_EQ(activeConfig, config) << "failed to get active config";
- }
- }
-}
-
-/* TESTCASE: Tests that the HWC2 does not return an active config for a bad
- * display. */
-TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_display)
-{
- hwc2_display_t display;
- hwc2_config_t activeConfig;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err));
-
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 either begins with a valid active config
- * or returns an error when getActiveConfig is called. */
-TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_config)
-{
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
- hwc2_config_t activeConfig;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- if (configs.empty())
- return;
-
- ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err));
- if (err == HWC2_ERROR_NONE) {
- EXPECT_NE(std::count(configs.begin(), configs.end(),
- activeConfig), 0) << "active config is not found in "
- " configs for display";
- } else {
- EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
- }
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can set every display config as an active
- * config */
-TEST_F(Hwc2Test, SET_ACTIVE_CONFIG)
-{
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- EXPECT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- }
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an active config for a bad display */
-TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_display)
-{
- hwc2_display_t display;
- const hwc2_config_t config = 0;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid active config */
-TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_config)
-{
- for (auto display : mDisplays) {
- hwc2_config_t config;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config));
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 returns a valid value for getDozeSupport. */
-TEST_F(Hwc2Test, GET_DOZE_SUPPORT)
-{
- for (auto display : mDisplays) {
- int32_t support = -1;
-
- ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
-
- EXPECT_TRUE(support == 0 || support == 1) << "invalid doze support value";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get doze support for a bad display. */
-TEST_F(Hwc2Test, GET_DOZE_SUPPORT_bad_display)
-{
- hwc2_display_t display;
- int32_t support = -1;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
-
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can set all supported power modes */
-TEST_F(Hwc2Test, SET_POWER_MODE)
-{
- for (auto display : mDisplays) {
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-
- int32_t support = -1;
- ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
- if (support != 1)
- return;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
- HWC2_POWER_MODE_DOZE_SUSPEND));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a power mode for a bad display. */
-TEST_F(Hwc2Test, SET_POWER_MODE_bad_display)
-{
- hwc2_display_t display;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
- int32_t support = -1;
- ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
- if (support != 1)
- return;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE_SUSPEND,
- &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid power mode value. */
-TEST_F(Hwc2Test, SET_POWER_MODE_bad_parameter)
-{
- for (auto display : mDisplays) {
- hwc2_power_mode_t mode = static_cast<hwc2_power_mode_t>(
- HWC2_POWER_MODE_DOZE_SUSPEND + 1);
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, mode, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code "
- << mode;
- }
-}
-
-/* TESTCASE: Tests that the HWC2 will return unsupported if it does not support
- * an optional power mode. */
-TEST_F(Hwc2Test, SET_POWER_MODE_unsupported)
-{
- for (auto display : mDisplays) {
- int32_t support = -1;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
- if (support == 1)
- return;
-
- ASSERT_EQ(support, 0) << "invalid doze support value";
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE,
- &err));
- EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
- HWC2_POWER_MODE_DOZE_SUSPEND, &err));
- EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can set the same power mode multiple times. */
-TEST_F(Hwc2Test, SET_POWER_MODE_stress)
-{
- for (auto display : mDisplays) {
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-
- int32_t support = -1;
- ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
- if (support != 1)
- return;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
- HWC2_POWER_MODE_DOZE_SUSPEND));
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
- HWC2_POWER_MODE_DOZE_SUSPEND));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can enable and disable vsync on active
- * displays */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED)
-{
- for (auto display : mDisplays) {
- hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
- const_cast<char*>("data"));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
- []() { return; }));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 issues a valid vsync callback. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_callback)
-{
- for (auto display : mDisplays) {
- hwc2_display_t receivedDisplay;
- int64_t receivedTimestamp;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(enableVsync(display));
-
- ASSERT_NO_FATAL_FAILURE(waitForVsync(&receivedDisplay,
- &receivedTimestamp));
-
- EXPECT_EQ(receivedDisplay, display) << "failed to get correct display";
- EXPECT_GE(receivedTimestamp, 0) << "failed to get valid timestamp";
-
- ASSERT_NO_FATAL_FAILURE(disableVsync(display));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot enable a vsync for a bad display */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_display)
-{
- hwc2_display_t display;
- hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
- const_cast<char*>("data"));
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
- []() { return; }));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot enable an invalid vsync value */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_parameter)
-{
- for (auto display : mDisplays) {
- hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
- const_cast<char*>("data"));
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
- []() { return; }));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_INVALID,
- &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can enable and disable a vsync value multiple
- * times. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_stress)
-{
- for (auto display : mDisplays) {
- hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
- const_cast<char*>("data"));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
- []() { return; }));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can set a vsync enable value when the display
- * is off and no callback is registered. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback_no_power)
-{
- const uint secs = 1;
-
- for (auto display : mDisplays) {
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
- sleep(secs);
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can set a vsync enable value when no callback
- * is registered. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback)
-{
- const uint secs = 1;
-
- for (auto display : mDisplays) {
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
- sleep(secs);
-
- ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 returns a display name for each display */
-TEST_F(Hwc2Test, GET_DISPLAY_NAME)
-{
- for (auto display : mDisplays) {
- std::string name;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 does not return a display name for a bad
- * display */
-TEST_F(Hwc2Test, GET_DISPLAY_NAME_bad_display)
-{
- hwc2_display_t display;
- std::string name;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can set basic composition types. */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setComposition, advanceComposition));
-}
-
-/* TESTCASE: Tests that the HWC2 can update a basic composition type on a
- * layer. */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setComposition, advanceComposition));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a composition type for a bad layer */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setComposition));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a bad composition type */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_parameter)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- hwc2_error_t* outErr) {
-
- ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
- layer, HWC2_COMPOSITION_INVALID, outErr));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- ::setCursorPosition, advanceCursorPosition));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the cursor position of a layer. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- ::setCursorPosition, advanceCursorPosition));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer when the
- * composition type has not been set to HWC2_COMPOSITION_CURSOR. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_composition_type_unset)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
- const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
- EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
- cursorPosition.left, cursorPosition.top, outErr));
- },
-
- advanceCursorPosition));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad
- * display. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_display)
-{
- hwc2_display_t display;
- hwc2_layer_t layer = 0;
- int32_t x = 0, y = 0;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(setCursorPosition(display, layer, x, y, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad layer. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
- const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
- EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display,
- badLayer, cursorPosition.left, cursorPosition.top,
- outErr));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set a blend mode value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setBlendMode, advanceBlendMode));
-}
-
-/* TESTCASE: Tests that the HWC2 can update a blend mode value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setBlendMode, advanceBlendMode));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a blend mode for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setBlendMode));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid blend mode. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_parameter)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- hwc2_error_t* outErr) {
-
- ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display,
- layer, HWC2_BLEND_MODE_INVALID, outErr));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the buffer of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setBuffer, advanceBuffer));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the buffer of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setBuffer, advanceBuffer));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the buffer of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
- buffer_handle_t handle = nullptr;
- android::base::unique_fd acquireFence;
-
- /* If there is not available buffer for the given buffer
- * properties, it should not fail this test case */
- if (testLayer->getBuffer(&handle, &acquireFence) == 0) {
- *outErr = HWC2_ERROR_BAD_LAYER;
- return;
- }
-
- ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, badLayer,
- handle, acquireFence, outErr));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set an invalid buffer for a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_parameter)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- hwc2_error_t* outErr) {
-
- buffer_handle_t handle = nullptr;
- int32_t acquireFence = -1;
-
- ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer,
- handle, acquireFence, outErr));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the color of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setColor, advanceColor));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the color of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setColor, advanceColor));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the color of a layer when the
- * composition type has not been set to HWC2_COMPOSITION_SOLID_COLOR. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR_composition_type_unset)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Basic,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
- EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer,
- testLayer->getColor(), outErr));
- },
-
- advanceColor));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the color of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
- Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
- EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, badLayer,
- testLayer->getColor(), outErr));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the dataspace of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DATASPACE)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setDataspace, advanceDataspace));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the dataspace of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DATASPACE_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setDataspace, advanceDataspace));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a dataspace for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_DATASPACE_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setDataspace));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the display frame of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setDisplayFrame, advanceDisplayFrame));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the display frame of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setDisplayFrame, advanceDisplayFrame));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the display frame of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setDisplayFrame));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the plane alpha of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setPlaneAlpha, advancePlaneAlpha));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the plane alpha of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setPlaneAlpha, advancePlaneAlpha));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a plane alpha for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
- Hwc2TestLayer* testLayer, hwc2_error_t *outErr) {
-
- EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display,
- badLayer, testLayer->getPlaneAlpha(), outErr));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the source crop of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setSourceCrop, advanceSourceCrop));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the source crop of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setSourceCrop, advanceSourceCrop));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the source crop of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setSourceCrop));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the surface damage of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setSurfaceDamage, advanceSurfaceDamage));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the surface damage of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setSurfaceDamage, advanceSurfaceDamage));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the surface damage of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setSurfaceDamage));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the transform value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_TRANSFORM)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
- setTransform, advanceTransform));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the transform value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_update)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
- setTransform, advanceTransform));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the transform for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setTransform));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the visible region of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Basic, 5,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayers* testLayers) {
-
- EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display,
- layer, testLayers->getVisibleRegion(layer)));
- },
-
- advanceVisibleRegions));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the visible region of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setVisibleRegion));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the z order of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_Z_ORDER)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Complete, 10,
- [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
- Hwc2TestLayers* testLayers) {
-
- EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer,
- testLayers->getZOrder(layer)));
- },
-
- /* TestLayer z orders are set during the construction of TestLayers
- * and cannot be updated. There is no need (or ability) to cycle
- * through additional z order configurations. */
- [] (Hwc2TestLayers* /*testLayers*/) {
- return false;
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the z order of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_update)
-{
- const std::vector<uint32_t> zOrders = { static_cast<uint32_t>(0),
- static_cast<uint32_t>(1), static_cast<uint32_t>(UINT32_MAX / 4),
- static_cast<uint32_t>(UINT32_MAX / 2),
- static_cast<uint32_t>(UINT32_MAX) };
-
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- hwc2_layer_t layer;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
- ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
- for (uint32_t zOrder : zOrders) {
- EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer, zOrder));
- }
-
- ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
- }
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the z order of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_bad_layer)
-{
- ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
- setZOrder));
-}
-
-/* TESTCASE: Tests that the HWC2 can display a layer with basic property
- * coverage */
-TEST_F(Hwc2Test, VALIDATE_DISPLAY_basic)
-{
- ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
- [] (Hwc2Test* test, hwc2_display_t display,
- const std::vector<hwc2_layer_t>& layers,
- Hwc2TestLayers* /*testLayers*/) {
-
- uint32_t numTypes, numRequests;
- bool hasChanges = false;
-
- EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
- if (hasChanges)
- EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
- << "wrong number of requests";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can display 5 layers with default coverage. */
-TEST_F(Hwc2Test, VALIDATE_DISPLAY_default_5)
-{
- ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 5,
- [] (Hwc2Test* test, hwc2_display_t display,
- const std::vector<hwc2_layer_t>& layers,
- Hwc2TestLayers* /*testLayers*/) {
-
- uint32_t numTypes, numRequests;
- bool hasChanges = false;
-
- EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
- if (hasChanges)
- EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
- << "wrong number of requests";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot validate a bad display */
-TEST_F(Hwc2Test, VALIDATE_DISPLAY_bad_display)
-{
- hwc2_display_t display;
- uint32_t numTypes, numRequests;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, &numRequests,
- &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can get display requests after validating a
- * basic layer. */
-TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_basic)
-{
- ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
- [] (Hwc2Test* test, hwc2_display_t display,
- const std::vector<hwc2_layer_t>& layers,
- Hwc2TestLayers* /*testLayers*/) {
-
- uint32_t numTypes, numRequests;
- bool hasChanges = false;
-
- ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
- if (hasChanges)
- EXPECT_LE(numTypes, layers.size())
- << "wrong number of requests";
-
- EXPECT_NO_FATAL_FAILURE(test->handleRequests(display, layers,
- numRequests));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get display requests from a bad display */
-TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_bad_display)
-{
- hwc2_display_t display;
- hwc2_display_request_t displayRequests;
- std::vector<hwc2_layer_t> layers;
- std::vector<hwc2_layer_request_t> layerRequests;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- EXPECT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequests,
- &layers, &layerRequests, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get display requests from an non
- * validated display. */
-TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_not_validated)
-{
- ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
- [] (Hwc2Test* test, hwc2_display_t display,
- std::vector<hwc2_layer_t>* layers) {
-
- hwc2_display_request_t displayRequests;
- std::vector<hwc2_layer_request_t> layerRequests;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->getDisplayRequests(display,
- &displayRequests, layers, &layerRequests, &err));
- EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
- << "returned wrong error code";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can get changed composition types after
- * validating a basic layer. */
-TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_basic)
-{
- ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
- [] (Hwc2Test* test, hwc2_display_t display,
- const std::vector<hwc2_layer_t>& layers,
- Hwc2TestLayers* testLayers) {
-
- uint32_t numTypes, numRequests;
- bool hasChanges = false;
-
- ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
- if (hasChanges)
- EXPECT_LE(numTypes, layers.size())
- << "wrong number of requests";
-
- EXPECT_NO_FATAL_FAILURE(test->handleCompositionChanges(display,
- *testLayers, layers, numTypes));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get changed composition types from a bad
- * display */
-TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_bad_display)
-{
- hwc2_display_t display;
- std::vector<hwc2_layer_t> layers;
- std::vector<hwc2_composition_t> types;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- EXPECT_NO_FATAL_FAILURE(getChangedCompositionTypes(display, &layers,
- &types, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get changed composition types from an non
- * validated display. */
-TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_not_validated)
-{
- ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
- [] (Hwc2Test* test, hwc2_display_t display,
- std::vector<hwc2_layer_t>* layers) {
-
- std::vector<hwc2_composition_t> types;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->getChangedCompositionTypes(
- display, layers, &types, &err));
- EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
- << "returned wrong error code";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can accept display changes after validating a
- * basic layer. */
-TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_basic)
-{
- ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
- [] (Hwc2Test* test, hwc2_display_t display,
- const std::vector<hwc2_layer_t>& layers,
- Hwc2TestLayers* testLayers) {
-
- uint32_t numTypes, numRequests;
- bool hasChanges = false;
-
- ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
- if (hasChanges)
- EXPECT_LE(numTypes, layers.size())
- << "wrong number of requests";
-
- ASSERT_NO_FATAL_FAILURE(test->handleCompositionChanges(display,
- *testLayers, layers, numTypes));
-
- EXPECT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot accept display changes from a bad
- * display */
-TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_bad_display)
-{
- hwc2_display_t display;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- EXPECT_NO_FATAL_FAILURE(acceptDisplayChanges(display, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot accept display changes from an non
- * validated display. */
-TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_not_validated)
-{
- ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
- [] (Hwc2Test* test, hwc2_display_t display,
- std::vector<hwc2_layer_t>* /*layers*/) {
-
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display, &err));
- EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
- << "returned wrong error code";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 supports client target with required values */
-TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT)
-{
- ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t display,
- const Hwc2TestClientTargetSupport& testClientTargetSupport) {
-
- const Area bufferArea = testClientTargetSupport.getBufferArea();
- const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
-
- ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display,
- bufferArea.width, bufferArea.height, format,
- testClientTargetSupport.getDataspace()));
- },
-
- advanceClientTargetSupport));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get client target support for a bad
- * display. */
-TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_bad_display)
-{
- ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t /*display*/,
- const Hwc2TestClientTargetSupport& testClientTargetSupport) {
-
- const Area bufferArea = testClientTargetSupport.getBufferArea();
- const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
- hwc2_display_t badDisplay;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
-
- ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(badDisplay,
- bufferArea.width, bufferArea.height, format,
- testClientTargetSupport.getDataspace(), &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
- },
-
- advanceClientTargetSupport));
-}
-
-/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported
- * for a variety of client target values. */
-TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_unsupported)
-{
- ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Complete,
- [] (Hwc2Test* test, hwc2_display_t display,
- const Hwc2TestClientTargetSupport& testClientTargetSupport) {
-
- const Area bufferArea = testClientTargetSupport.getBufferArea();
- const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display,
- bufferArea.width, bufferArea.height, format,
- testClientTargetSupport.getDataspace(), &err));
- EXPECT_TRUE(err == HWC2_ERROR_NONE
- || err == HWC2_ERROR_UNSUPPORTED)
- << "returned wrong error code";
- },
-
- advanceClientTargetSupport));
-}
-
-/* TESTCASE: Tests that the HWC2 can set a client target buffer for a basic
- * layer. */
-TEST_F(Hwc2Test, SET_CLIENT_TARGET_basic)
-{
- const Dataspace dataspace = Dataspace::UNKNOWN;
- const hwc_region_t damage = { };
- const size_t layerCnt = 1;
-
- for (auto display : mDisplays) {
- std::vector<hwc2_config_t> configs;
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
- ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
- for (auto config : configs) {
- Area displayArea;
- std::vector<hwc2_layer_t> layers;
-
- ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
- ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea));
-
- ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
- Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Basic,
- displayArea);
-
- if (!testLayers.optimizeLayouts())
- continue;
-
- Hwc2TestClientTarget testClientTarget;
-
- do {
- std::set<hwc2_layer_t> clientLayers;
- std::set<hwc2_layer_t> clearLayers;
- uint32_t numTypes, numRequests;
- bool hasChanges, skip;
- bool flipClientTarget;
- buffer_handle_t handle;
- int32_t acquireFence;
-
- ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
- &testLayers, &skip));
- if (skip)
- continue;
-
- ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
- &numRequests, &hasChanges));
- if (hasChanges)
- EXPECT_LE(numTypes, layers.size())
- << "wrong number of requests";
-
- ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
- testLayers, layers, numTypes, &clientLayers));
- ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
- numRequests, &clearLayers, &flipClientTarget));
- ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers,
- clearLayers, flipClientTarget, displayArea, &handle,
- &acquireFence), 0);
- EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle,
- acquireFence, dataspace, damage));
-
- if (acquireFence >= 0)
- close(acquireFence);
-
- } while (testLayers.advance());
-
- ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
- }
-
- ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a client target for a bad display. */
-TEST_F(Hwc2Test, SET_CLIENT_TARGET_bad_display)
-{
- hwc2_display_t display;
- std::vector<hwc2_layer_t> layers;
- const Area displayArea = {0, 0};
- Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Default, displayArea);
- std::set<hwc2_layer_t> clientLayers;
- std::set<hwc2_layer_t> flipClientTargetLayers;
- bool flipClientTarget = true;
- const Dataspace dataspace = Dataspace::UNKNOWN;
- const hwc_region_t damage = { };
- buffer_handle_t handle;
- int32_t acquireFence;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- Hwc2TestClientTarget testClientTarget;
-
- ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers,
- flipClientTargetLayers, flipClientTarget, displayArea, &handle,
- &acquireFence), 0);
-
- EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence,
- dataspace, damage, &err));
-
- if (acquireFence >= 0)
- close(acquireFence);
-
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 default layer. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 3 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_3)
-{
- const size_t layerCnt = 3;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 4 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_4)
-{
- const size_t layerCnt = 4;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 5 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_5)
-{
- const size_t layerCnt = 5;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 6 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_6)
-{
- const size_t layerCnt = 6;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * blend mode. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Basic},
- {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}};
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * blend mode. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}};
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * buffer. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_buffer_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * color. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_color_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * color. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_color_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
- {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic},
- {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Basic}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * composition. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_composition_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * cursor. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * cursor. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * dataspace. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_dataspace_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 3 layers with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_3)
-{
- const size_t layerCnt = 3;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 4 layers with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_4)
-{
- const size_t layerCnt = 4;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * plane alpha. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
- {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}};
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * plane alpha. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
- {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}};
- bool optimize = false;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * source crop. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * source crop. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * surface damage. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_surface_damage_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::SurfaceDamage, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * transform. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * transform. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_2)
-{
- const size_t layerCnt = 2;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
- {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete},
- {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}};
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * basic. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_basic_1)
-{
- const size_t layerCnt = 1;
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
- bool optimize = true;
-
- ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
- optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot present a bad display. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_bad_display)
-{
- hwc2_display_t display;
- int32_t presentFence;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(presentDisplay(display, &presentFence, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot present an unvalidated display. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_not_validated)
-{
- ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 1,
- [] (Hwc2Test* test, hwc2_display_t display,
- const std::vector<hwc2_layer_t>& /*layers*/,
- Hwc2TestLayers* /*testLayers*/) {
-
- int32_t presentFence;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display,
- HWC2_POWER_MODE_ON));
- ASSERT_NO_FATAL_FAILURE(test->enableVsync(display));
-
- ASSERT_NO_FATAL_FAILURE(test->waitForVsync());
-
- ASSERT_NO_FATAL_FAILURE(test->presentDisplay(display,
- &presentFence, &err));
- EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
- << "returned wrong error code";
-
- ASSERT_NO_FATAL_FAILURE(test->disableVsync(display));
- ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display,
- HWC2_POWER_MODE_OFF));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get release fences from a bad display. */
-TEST_F(Hwc2Test, GET_RELEASE_FENCES_bad_display)
-{
- hwc2_display_t display;
- std::vector<hwc2_layer_t> layers;
- std::vector<int32_t> fences;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-static const std::array<ColorMode, 9> androidColorModes = {{
- ColorMode::NATIVE,
- ColorMode::STANDARD_BT601_625,
- ColorMode::STANDARD_BT601_625_UNADJUSTED,
- ColorMode::STANDARD_BT601_525,
- ColorMode::STANDARD_BT601_525_UNADJUSTED,
- ColorMode::STANDARD_BT709,
- ColorMode::DCI_P3,
- ColorMode::SRGB,
- ColorMode::ADOBE_RGB,
-}};
-
-/* TESTCASE: Tests that the HWC2 can get the color modes for a display. The
- * display must support ColorMode::NATIVE */
-TEST_F(Hwc2Test, GET_COLOR_MODES)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- std::vector<ColorMode> colorModes;
-
- ASSERT_NO_FATAL_FAILURE(test->getColorModes(display,
- &colorModes));
-
- EXPECT_NE(std::count(colorModes.begin(), colorModes.end(),
- ColorMode::NATIVE), 0) << "all displays"
- " must support ColorMode::NATIVE";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get color modes from a bad display. */
-TEST_F(Hwc2Test, GET_COLOR_MODES_bad_display)
-{
- hwc2_display_t display;
- std::vector<ColorMode> colorModes;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getColorModes(display, &colorModes, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can set the required color mode on a display. */
-TEST_F(Hwc2Test, SET_COLOR_MODES)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- const ColorMode colorMode = ColorMode::NATIVE;
-
- EXPECT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a color mode on a bad display. */
-TEST_F(Hwc2Test, SET_COLOR_MODES_bad_display)
-{
- hwc2_display_t display;
- const ColorMode colorMode = ColorMode::NATIVE;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(setColorMode(display, colorMode, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid color mode. */
-TEST_F(Hwc2Test, SET_COLOR_MODES_bad_parameter)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- const ColorMode colorMode = static_cast<ColorMode>(-1);
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode,
- &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
- << "returned wrong error code";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported
- * for all valid color modes. */
-TEST_F(Hwc2Test, SET_COLOR_MODES_unsupported)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- for (auto colorMode : androidColorModes) {
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->setColorMode(display,
- colorMode, &err));
-
- EXPECT_TRUE(err == HWC2_ERROR_NONE
- || err == HWC2_ERROR_UNSUPPORTED)
- << "returned wrong error code";
- }
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 gets the HDR capabilities for a display and
- * test if they are valid. */
-TEST_F(Hwc2Test, GET_HDR_CAPABILITIES)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- std::vector<android_hdr_t> hdrCapabilities;
- float maxLuminance, maxAverageLuminance, minLuminance;
-
- EXPECT_NO_FATAL_FAILURE(test->getHdrCapabilities(display,
- &hdrCapabilities, &maxLuminance, &maxAverageLuminance,
- &minLuminance));
-
- if (hdrCapabilities.empty())
- return;
-
- EXPECT_GE(maxLuminance, maxAverageLuminance);
- EXPECT_GE(maxAverageLuminance, minLuminance);
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get hdr capabilities from a bad display */
-TEST_F(Hwc2Test, GET_HDR_CAPABILITIES_bad_display)
-{
- hwc2_display_t display;
- std::vector<android_hdr_t> hdrCapabilities;
- float maxLuminance, maxAverageLuminance, minLuminance;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(getHdrCapabilities(display, &hdrCapabilities,
- &maxLuminance, &maxAverageLuminance, &minLuminance, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-static const std::array<float, 16> identityMatrix = {{
- 1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0,
-}};
-
-/* Values for the color transform matrices were precomputed using the source code
- * in surfaceflinger/Effects/Daltonizer.cpp. */
-
-static const std::array<const std::array<float, 16>, 5> exampleMatrices = {{
- identityMatrix,
- /* Converts RGB color to the XYZ space */
- {{ 0.4124, 0.2126, 0.0193, 0,
- 0.3576, 0.7152, 0.1192, 0,
- 0.1805, 0.0722, 0.9505, 0,
- 0 , 0 , 0 , 1 }},
- /* Protanomaly */
- {{ 0.068493, 0.931506, 0, 0,
- 0.068493, 0.931507, 0, 0,
- 0.013626, -0.013626, 1, 0,
- 0, 0, 0, 1 }},
- /* Deuteranomaly */
- {{ 0.288299, 0.711701, 0, 0,
- 0.052709, 0.947291, 0, 0,
- -0.257912, 0.257912, 1, 0,
- 0, 0, 0, 1 }},
- /* Tritanomaly */
- {{ 1, -0.805712, 0.805712, 0,
- 0, 0.378838, 0.621162, 0,
- 0, 0.104823, 0.895177, 0,
- 0, 0, 0, 1 }},
-}};
-
-/* TESTCASE: Tests that the HWC2 can set the identity color transform */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display,
- identityMatrix, HAL_COLOR_TRANSFORM_IDENTITY));
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the color transform for a bad
- * display. */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_display)
-{
- hwc2_display_t display;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(setColorTransform(display, identityMatrix,
- HAL_COLOR_TRANSFORM_IDENTITY, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid color transform. */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_parameter)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- const android_color_transform_t hint =
- static_cast<android_color_transform_t>(-1);
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->setColorTransform(display,
- identityMatrix, hint, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
- << "returned wrong error code";
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set an arbitrary color matrix. */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_arbitrary_matrix)
-{
- ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
- [] (Hwc2Test* test, hwc2_display_t display) {
-
- const android_color_transform_t hint =
- HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-
- for (const std::array<float, 16>& matrix : exampleMatrices) {
- EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display,
- matrix, hint));
- }
- }
- ));
-}
-
-/* TESTCASE: Tests that the HWC2 create an destory virtual displays. */
-TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY)
-{
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete,
- [] (Hwc2Test* /*test*/, hwc2_display_t /*display*/,
- Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) { }));
-}
-
-/* TESTCASE: Tests that the HWC2 can create and destroy multiple virtual
- * displays. */
-TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY_multiple)
-{
- Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete);
- std::vector<hwc2_display_t> displays;
-
- do {
- const UnsignedArea& dimension =
- testVirtualDisplay.getDisplayDimension();
- android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
- hwc2_display_t display;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
- dimension.height, &desiredFormat, &display, &err));
-
- EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES
- || err == HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
- EXPECT_GE(desiredFormat, 0) << "invalid format";
-
- if (err == HWC2_ERROR_NONE)
- displays.push_back(display);
-
- } while (testVirtualDisplay.advance());
-
- for (hwc2_display_t display : displays) {
- EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destroy a bad virtual displays. */
-TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_display)
-{
- hwc2_display_t display;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
- ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */
-TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter)
-{
- hwc2_error_t err = HWC2_ERROR_NONE;
- for (auto display : mDisplays) {
- ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can get the max virtual display count. */
-TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT)
-{
- uint32_t maxCnt;
-
- ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt));
-}
-
-/* TESTCASE: Tests that the HWC2 returns the same max virtual display count for
- * each call. */
-TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_duplicate)
-{
- uint32_t maxCnt1, maxCnt2;
-
- ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt1));
- ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt2));
-
- EXPECT_EQ(maxCnt1, maxCnt2) << "returned two different max virtual display"
- " counts";
-}
-
-/* TESTCASE: Tests that the HWC2 can create the max number of virtual displays
- * that it reports. */
-TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_create_max)
-{
- std::vector<hwc2_display_t> displays;
- uint32_t maxCnt;
-
- ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt));
-
- while (displays.size() < maxCnt) {
- uint32_t width = 1920, height = 1080;
- android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
- hwc2_display_t display;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(width, height,
- &desiredFormat, &display, &err));
-
- EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED)
- << "returned wrong error code";
- if (err != HWC2_ERROR_NONE)
- break;
-
- displays.push_back(display);
- }
-
- for (hwc2_display_t display : displays) {
- EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can set an output buffer for a virtual
- * display. */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER)
-{
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete,
- [] (Hwc2Test* test, hwc2_display_t display,
- Hwc2TestVirtualDisplay* testVirtualDisplay) {
-
- buffer_handle_t handle;
- android::base::unique_fd acquireFence;
-
- if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0)
- EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display,
- handle, acquireFence));
- }));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an output buffer for a bad display */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_display)
-{
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t /*display*/,
- Hwc2TestVirtualDisplay* testVirtualDisplay) {
-
- hwc2_display_t badDisplay;
- buffer_handle_t handle;
- android::base::unique_fd acquireFence;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
-
- if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0)
- return;
-
- ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay,
- handle, acquireFence, &err));
- EXPECT_TRUE(err == HWC2_ERROR_BAD_DISPLAY)
- << "returned wrong error code";
- }));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid output buffer. */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_parameter)
-{
- ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default,
- [] (Hwc2Test* test, hwc2_display_t display,
- Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) {
-
- const buffer_handle_t handle = nullptr;
- uint32_t releaseFence = -1;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(display, handle,
- releaseFence, &err));
- EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
- << "returned wrong error code";
- }));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an output buffer for non virtual
- * display */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_unsupported)
-{
- for (auto display : mDisplays) {
- Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete);
-
- do {
- buffer_handle_t handle;
- android::base::unique_fd acquireFence;
- hwc2_error_t err = HWC2_ERROR_NONE;
-
- if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0)
- continue;
-
- ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle,
- acquireFence, &err));
- EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
-
- } while (testVirtualDisplay.advance());
- }
-}
-
-/* TESTCASE: Tests that the HWC2 can dump debug information. */
-TEST_F(Hwc2Test, DUMP)
-{
- std::string buffer;
-
- ASSERT_NO_FATAL_FAILURE(dump(&buffer));
-}
-
-/*
- * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all
- * virtual display tests as we don't handle this case correctly.
- *
- * Only default dataspace is supported in our drawing code.
- */
-const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>
- virtualDisplayExceptions =
- {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default},
- {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}};
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1)
-{
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- const size_t layerCnt = 1;
- ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
- virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1)
-{
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
- const size_t layerCnt = 1;
- ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
- virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2)
-{
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- const size_t layerCnt = 2;
- ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
- virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3)
-{
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- const size_t layerCnt = 3;
- ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
- virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4)
-{
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- const size_t layerCnt = 4;
- ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
- virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5)
-{
- Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
- const size_t layerCnt = 5;
- ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
- virtualDisplayExceptions));
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
deleted file mode 100644
index 6484562..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ /dev/null
@@ -1,791 +0,0 @@
-/*
- * Copyright (C) 2016 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 <mutex>
-#include <array>
-#include <sstream>
-#include <algorithm>
-
-#include <gui/Surface.h>
-#include <gui/BufferItemConsumer.h>
-
-#include <ui/GraphicBuffer.h>
-#include <android/hardware/graphics/common/1.0/types.h>
-#include <math/vec4.h>
-
-#include <GLES3/gl3.h>
-#include <SkImageEncoder.h>
-#include <SkStream.h>
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestLayers.h"
-
-using namespace android;
-using android::hardware::graphics::common::V1_0::BufferUsage;
-
-/* Returns a fence from egl */
-typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
-
-/* Returns fence to fence generator */
-static void setFence(int32_t fence, void* fenceGenerator);
-
-
-/* Used to receive the surfaces and fences from egl. The egl buffers are thrown
- * away. The fences are sent to the requester via a callback */
-class Hwc2TestSurfaceManager {
-public:
- /* Listens for a new frame, detaches the buffer and returns the fence
- * through saved callback. */
- class BufferListener : public ConsumerBase::FrameAvailableListener {
- public:
- BufferListener(sp<IGraphicBufferConsumer> consumer,
- FenceCallback callback, void* callbackArgs)
- : mConsumer(consumer),
- mCallback(callback),
- mCallbackArgs(callbackArgs) { }
-
- void onFrameAvailable(const BufferItem& /*item*/)
- {
- BufferItem item;
-
- if (mConsumer->acquireBuffer(&item, 0))
- return;
- if (mConsumer->detachBuffer(item.mSlot))
- return;
-
- mCallback(item.mFence->dup(), mCallbackArgs);
- }
-
- private:
- sp<IGraphicBufferConsumer> mConsumer;
- FenceCallback mCallback;
- void* mCallbackArgs;
- };
-
- /* Creates a buffer listener that waits on a new frame from the buffer
- * queue. */
- void initialize(const Area& bufferArea, android_pixel_format_t format,
- FenceCallback callback, void* callbackArgs)
- {
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
-
- consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height);
- consumer->setDefaultBufferFormat(format);
-
- mBufferItemConsumer = new BufferItemConsumer(consumer, 0);
-
- mListener = new BufferListener(consumer, callback, callbackArgs);
- mBufferItemConsumer->setFrameAvailableListener(mListener);
-
- mSurface = new Surface(producer, true);
- }
-
- /* Used by Egl manager. The surface is never displayed. */
- sp<Surface> getSurface() const
- {
- return mSurface;
- }
-
-private:
- sp<BufferItemConsumer> mBufferItemConsumer;
- sp<BufferListener> mListener;
- /* Used by Egl manager. The surface is never displayed */
- sp<Surface> mSurface;
-};
-
-
-/* Used to generate valid fences. It is not possible to create a dummy sync
- * fence for testing. Egl can generate buffers along with a valid fence.
- * The buffer cannot be guaranteed to be the same format across all devices so
- * a CPU filled buffer is used instead. The Egl fence is used along with the
- * CPU filled buffer. */
-class Hwc2TestEglManager {
-public:
- Hwc2TestEglManager()
- : mEglDisplay(EGL_NO_DISPLAY),
- mEglSurface(EGL_NO_SURFACE),
- mEglContext(EGL_NO_CONTEXT) { }
-
- ~Hwc2TestEglManager()
- {
- cleanup();
- }
-
- int initialize(sp<Surface> surface)
- {
- mSurface = surface;
-
- mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (mEglDisplay == EGL_NO_DISPLAY) return false;
-
- EGLint major;
- EGLint minor;
- if (!eglInitialize(mEglDisplay, &major, &minor)) {
- ALOGW("Could not initialize EGL");
- return false;
- }
-
- /* We're going to use a 1x1 pbuffer surface later on
- * The configuration distance doesn't really matter for what we're
- * trying to do */
- EGLint configAttrs[] = {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 0,
- EGL_DEPTH_SIZE, 24,
- EGL_STENCIL_SIZE, 0,
- EGL_NONE
- };
-
- EGLConfig configs[1];
- EGLint configCnt;
- if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1,
- &configCnt)) {
- ALOGW("Could not select EGL configuration");
- eglReleaseThread();
- eglTerminate(mEglDisplay);
- return false;
- }
-
- if (configCnt <= 0) {
- ALOGW("Could not find EGL configuration");
- eglReleaseThread();
- eglTerminate(mEglDisplay);
- return false;
- }
-
- /* These objects are initialized below but the default "null" values are
- * used to cleanup properly at any point in the initialization sequence */
- EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
- mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT,
- attrs);
- if (mEglContext == EGL_NO_CONTEXT) {
- ALOGW("Could not create EGL context");
- cleanup();
- return false;
- }
-
- EGLint surfaceAttrs[] = { EGL_NONE };
- mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0],
- mSurface.get(), surfaceAttrs);
- if (mEglSurface == EGL_NO_SURFACE) {
- ALOGW("Could not create EGL surface");
- cleanup();
- return false;
- }
-
- if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
- ALOGW("Could not change current EGL context");
- cleanup();
- return false;
- }
-
- return true;
- }
-
- void makeCurrent() const
- {
- eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
- }
-
- void present() const
- {
- eglSwapBuffers(mEglDisplay, mEglSurface);
- }
-
-private:
- void cleanup()
- {
- if (mEglDisplay == EGL_NO_DISPLAY)
- return;
- if (mEglSurface != EGL_NO_SURFACE)
- eglDestroySurface(mEglDisplay, mEglSurface);
- if (mEglContext != EGL_NO_CONTEXT)
- eglDestroyContext(mEglDisplay, mEglContext);
-
- eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
- EGL_NO_CONTEXT);
- eglReleaseThread();
- eglTerminate(mEglDisplay);
- }
-
- sp<Surface> mSurface;
- EGLDisplay mEglDisplay;
- EGLSurface mEglSurface;
- EGLContext mEglContext;
-};
-
-
-static const std::array<vec2, 4> triangles = {{
- { 1.0f, 1.0f },
- { -1.0f, 1.0f },
- { 1.0f, -1.0f },
- { -1.0f, -1.0f },
-}};
-
-class Hwc2TestFenceGenerator {
-public:
-
- Hwc2TestFenceGenerator()
- {
- mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888,
- setFence, this);
-
- if (!mEglManager.initialize(mSurfaceManager.getSurface()))
- return;
-
- mEglManager.makeCurrent();
-
- glClearColor(0.0, 0.0, 0.0, 1.0);
- glEnableVertexAttribArray(0);
- }
-
- ~Hwc2TestFenceGenerator()
- {
- if (mFence >= 0)
- close(mFence);
- mFence = -1;
-
- mEglManager.makeCurrent();
- }
-
- /* It is not possible to simply generate a fence. The easiest way is to
- * generate a buffer using egl and use the associated fence. The buffer
- * cannot be guaranteed to be a certain format across all devices using this
- * method. Instead the buffer is generated using the CPU */
- int32_t get()
- {
- if (mFence >= 0) {
- return dup(mFence);
- }
-
- std::unique_lock<std::mutex> lock(mMutex);
-
- /* If the pending is still set to false and times out, we cannot recover.
- * Set an error and return */
- while (mPending != false) {
- if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
- return -ETIME;
- }
-
- /* Generate a fence. The fence will be returned through the setFence
- * callback */
- mEglManager.makeCurrent();
-
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data());
- glClear(GL_COLOR_BUFFER_BIT);
-
- mEglManager.present();
-
- /* Wait for the setFence callback */
- while (mPending != true) {
- if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
- return -ETIME;
- }
-
- mPending = false;
-
- return dup(mFence);
- }
-
- /* Callback that sets the fence */
- void set(int32_t fence)
- {
- mFence = fence;
- mPending = true;
-
- mCv.notify_all();
- }
-
-private:
-
- Hwc2TestSurfaceManager mSurfaceManager;
- Hwc2TestEglManager mEglManager;
-
- std::mutex mMutex;
- std::condition_variable mCv;
-
- int32_t mFence = -1;
- bool mPending = false;
-};
-
-
-static void setFence(int32_t fence, void* fenceGenerator)
-{
- static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence);
-}
-
-
-/* Sets the pixel of a buffer given the location, format, stride and color.
- * Currently only supports RGBA_8888 */
-static void setColor(int32_t x, int32_t y,
- android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r,
- uint8_t g, uint8_t b, uint8_t a)
-{
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- img[(y * stride + x) * 4 + 0] = r;
- img[(y * stride + x) * 4 + 1] = g;
- img[(y * stride + x) * 4 + 2] = b;
- img[(y * stride + x) * 4 + 3] = a;
- break;
- default:
- break;
- }
-}
-
-Hwc2TestBuffer::Hwc2TestBuffer()
- : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
-
-Hwc2TestBuffer::~Hwc2TestBuffer() = default;
-
-/* When the buffer changes sizes, save the new size and invalidate the current
- * buffer */
-void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea)
-{
- if (mBufferArea.width == bufferArea.width
- && mBufferArea.height == bufferArea.height)
- return;
-
- mBufferArea.width = bufferArea.width;
- mBufferArea.height = bufferArea.height;
-
- mValidBuffer = false;
-}
-
-/* Returns a valid buffer handle and fence. The handle is filled using the CPU
- * to ensure the correct format across all devices. The fence is created using
- * egl. */
-int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence)
-{
- if (mBufferArea.width == -1 || mBufferArea.height == -1)
- return -EINVAL;
-
- /* If the current buffer is valid, the previous buffer can be reused.
- * Otherwise, create new buffer */
- if (!mValidBuffer) {
- int ret = generateBuffer();
- if (ret)
- return ret;
- }
-
- *outFence = mFenceGenerator->get();
- *outHandle = mHandle;
-
- mValidBuffer = true;
-
- return 0;
-}
-
-/* CPU fills a buffer to guarantee the correct buffer format across all
- * devices */
-int Hwc2TestBuffer::generateBuffer()
-{
- /* Create new graphic buffer with correct dimensions */
- mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
- mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
-
- int ret = mGraphicBuffer->initCheck();
- if (ret) {
- return ret;
- }
- if (!mGraphicBuffer->handle) {
- return -EINVAL;
- }
-
- /* Locks the buffer for writing */
- uint8_t* img;
- mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
- (void**)(&img));
-
- uint32_t stride = mGraphicBuffer->getStride();
-
- /* Iterate from the top row of the buffer to the bottom row */
- for (int32_t y = 0; y < mBufferArea.height; y++) {
-
- /* Will be used as R, G and B values for pixel colors */
- uint8_t max = 255;
- uint8_t min = 0;
-
- /* Divide the rows into 3 sections. The first section will contain
- * the lighest colors. The last section will contain the darkest
- * colors. */
- if (y < mBufferArea.height * 1.0 / 3.0) {
- min = 255 / 2;
- } else if (y >= mBufferArea.height * 2.0 / 3.0) {
- max = 255 / 2;
- }
-
- /* Divide the columns into 3 sections. The first section is red,
- * the second is green and the third is blue */
- int32_t x = 0;
- for (; x < mBufferArea.width / 3; x++) {
- setColor(x, y, mFormat, stride, img, max, min, min, 255);
- }
-
- for (; x < mBufferArea.width * 2 / 3; x++) {
- setColor(x, y, mFormat, stride, img, min, max, min, 255);
- }
-
- for (; x < mBufferArea.width; x++) {
- setColor(x, y, mFormat, stride, img, min, min, max, 255);
- }
- }
-
- /* Unlock the buffer for reading */
- mGraphicBuffer->unlock();
-
- mHandle = mGraphicBuffer->handle;
-
- return 0;
-}
-
-
-Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
- : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
-
-Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
-
-/* Generates a buffer from layersToDraw.
- * Takes into account the individual layer properties such as
- * transform, blend mode, source crop, etc. */
-static void compositeBufferFromLayers(
- const android::sp<android::GraphicBuffer>& graphicBuffer,
- android_pixel_format_t format, const Area& bufferArea,
- const Hwc2TestLayers* testLayers,
- const std::set<hwc2_layer_t>* layersToDraw,
- const std::set<hwc2_layer_t>* clearLayers)
-{
- /* Locks the buffer for writing */
- uint8_t* img;
- graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
- (void**)(&img));
-
- uint32_t stride = graphicBuffer->getStride();
-
- float bWDiv3 = bufferArea.width / 3;
- float bW2Div3 = bufferArea.width * 2 / 3;
- float bHDiv3 = bufferArea.height / 3;
- float bH2Div3 = bufferArea.height * 2 / 3;
-
- /* Cycle through every pixel in the buffer and determine what color it
- * should be. */
- for (int32_t y = 0; y < bufferArea.height; y++) {
- for (int32_t x = 0; x < bufferArea.width; x++) {
-
- uint8_t r = 0, g = 0, b = 0;
- float a = 0.0f;
-
- /* Cycle through each layer from back to front and
- * update the pixel color. */
- for (auto layer = layersToDraw->rbegin();
- layer != layersToDraw->rend(); ++layer) {
-
- const hwc_rect_t df = testLayers->getDisplayFrame(*layer);
-
- float dfL = df.left;
- float dfT = df.top;
- float dfR = df.right;
- float dfB = df.bottom;
-
- /* If the pixel location falls outside of the layer display
- * frame, skip the layer. */
- if (x < dfL || x >= dfR || y < dfT || y >= dfB)
- continue;
-
- /* If the device has requested the layer be clear, clear
- * the pixel and continue. */
- if (clearLayers->count(*layer) != 0) {
- r = 0;
- g = 0;
- b = 0;
- a = 0.0f;
- continue;
- }
-
- float planeAlpha = testLayers->getPlaneAlpha(*layer);
-
- /* If the layer is a solid color, fill the color and
- * continue. */
- if (testLayers->getComposition(*layer)
- == HWC2_COMPOSITION_SOLID_COLOR) {
- const auto color = testLayers->getColor(*layer);
- r = color.r;
- g = color.g;
- b = color.b;
- a = color.a * planeAlpha;
- continue;
- }
-
- float xPos = x;
- float yPos = y;
-
- hwc_transform_t transform = testLayers->getTransform(*layer);
-
- float dfW = dfR - dfL;
- float dfH = dfB - dfT;
-
- /* If a layer has a transform, find which location on the
- * layer will end up in the current pixel location. We
- * can calculate the color of the current pixel using that
- * location. */
- if (transform > 0) {
- /* Change origin to be the center of the layer. */
- xPos = xPos - dfL - dfW / 2.0;
- yPos = yPos - dfT - dfH / 2.0;
-
- /* Flip Horizontal by reflecting across the y axis. */
- if (transform & HWC_TRANSFORM_FLIP_H)
- xPos = -xPos;
-
- /* Flip vertical by reflecting across the x axis. */
- if (transform & HWC_TRANSFORM_FLIP_V)
- yPos = -yPos;
-
- /* Rotate 90 by using a basic linear algebra rotation
- * and scaling the result so the display frame remains
- * the same. For example, a buffer of size 100x50 should
- * rotate 90 degress but remain the same dimension
- * (100x50) at the end of the transformation. */
- if (transform & HWC_TRANSFORM_ROT_90) {
- float tmp = xPos;
- xPos = yPos * dfW / dfH;
- yPos = -tmp * dfH / dfW;
- }
-
- /* Change origin back to the top left corner of the
- * layer. */
- xPos = xPos + dfL + dfW / 2.0;
- yPos = yPos + dfT + dfH / 2.0;
- }
-
- hwc_frect_t sc = testLayers->getSourceCrop(*layer);
- float scL = sc.left, scT = sc.top;
-
- float dfWDivScW = dfW / (sc.right - scL);
- float dfHDivScH = dfH / (sc.bottom - scT);
-
- float max = 255, min = 0;
-
- /* Choose the pixel color. Similar to generateBuffer,
- * each layer will be divided into 3x3 colors. Because
- * both the source crop and display frame must be taken into
- * account, the formulas are more complicated.
- *
- * If the source crop and display frame were not taken into
- * account, we would simply divide the buffer into three
- * sections by height. Each section would get one color.
- * For example the formula for the first section would be:
- *
- * if (yPos < bufferArea.height / 3)
- * //Select first section color
- *
- * However the pixel color is chosen based on the source
- * crop and displayed based on the display frame.
- *
- * If the display frame top was 0 and the source crop height
- * and display frame height were the same. The only factor
- * would be the source crop top. To calculate the new
- * section boundary, the section boundary would be moved up
- * by the height of the source crop top. The formula would
- * be:
- * if (yPos < (bufferArea.height / 3 - sourceCrop.top)
- * //Select first section color
- *
- * If the display frame top could also vary but source crop
- * and display frame heights were the same, the formula
- * would be:
- * if (yPos < (bufferArea.height / 3 - sourceCrop.top
- * + displayFrameTop)
- * //Select first section color
- *
- * If the heights were not the same, the conversion between
- * the source crop and display frame dimensions must be
- * taken into account. The formula would be:
- * if (yPos < ((bufferArea.height / 3) - sourceCrop.top)
- * * displayFrameHeight / sourceCropHeight
- * + displayFrameTop)
- * //Select first section color
- */
- if (yPos < ((bHDiv3) - scT) * dfHDivScH + dfT) {
- min = 255 / 2;
- } else if (yPos >= ((bH2Div3) - scT) * dfHDivScH + dfT) {
- max = 255 / 2;
- }
-
- uint8_t rCur = min, gCur = min, bCur = min;
- float aCur = 1.0f;
-
- /* This further divides the color sections from 3 to 3x3.
- * The math behind it follows the same logic as the previous
- * comment */
- if (xPos < ((bWDiv3) - scL) * (dfWDivScW) + dfL) {
- rCur = max;
- } else if (xPos < ((bW2Div3) - scL) * (dfWDivScW) + dfL) {
- gCur = max;
- } else {
- bCur = max;
- }
-
-
- /* Blend the pixel color with the previous layers' pixel
- * colors using the plane alpha and blend mode. The final
- * pixel color is chosen using the plane alpha and blend
- * mode formulas found in hwcomposer2.h */
- hwc2_blend_mode_t blendMode = testLayers->getBlendMode(*layer);
-
- if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
- rCur *= planeAlpha;
- gCur *= planeAlpha;
- bCur *= planeAlpha;
- }
-
- aCur *= planeAlpha;
-
- if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
- r = rCur + r * (1.0 - aCur);
- g = gCur + g * (1.0 - aCur);
- b = bCur + b * (1.0 - aCur);
- a = aCur + a * (1.0 - aCur);
- } else if (blendMode == HWC2_BLEND_MODE_COVERAGE) {
- r = rCur * aCur + r * (1.0 - aCur);
- g = gCur * aCur + g * (1.0 - aCur);
- b = bCur * aCur + b * (1.0 - aCur);
- a = aCur * aCur + a * (1.0 - aCur);
- } else {
- r = rCur;
- g = gCur;
- b = bCur;
- a = aCur;
- }
- }
-
- /* Set the pixel color */
- setColor(x, y, format, stride, img, r, g, b, a * 255);
- }
- }
-
- graphicBuffer->unlock();
-}
-
-/* Generates a client target buffer using the layers assigned for client
- * composition. Takes into account the individual layer properties such as
- * transform, blend mode, source crop, etc. */
-int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
- int32_t* outFence, const Area& bufferArea,
- const Hwc2TestLayers* testLayers,
- const std::set<hwc2_layer_t>* clientLayers,
- const std::set<hwc2_layer_t>* clearLayers)
-{
- /* Create new graphic buffer with correct dimensions */
- mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
- mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
-
- int ret = mGraphicBuffer->initCheck();
- if (ret)
- return ret;
-
- if (!mGraphicBuffer->handle)
- return -EINVAL;
-
- compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers,
- clientLayers, clearLayers);
-
- *outFence = mFenceGenerator->get();
- *outHandle = mGraphicBuffer->handle;
-
- return 0;
-}
-
-void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
-{
- mBufferArea.width = bufferArea.width;
- mBufferArea.height = bufferArea.height;
-}
-
-bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path)
-{
- SkFILEWStream file(path.c_str());
- const SkImageInfo info = SkImageInfo::Make(mBufferArea.width,
- mBufferArea.height, SkColorType::kRGBA_8888_SkColorType,
- SkAlphaType::kPremul_SkAlphaType);
-
- uint8_t* img;
- mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
- (void**)(&img));
-
- SkPixmap pixmap(info, img, mGraphicBuffer->getStride());
- bool result = file.isValid() && SkEncodeImage(&file, pixmap,
- SkEncodedImageFormat::kPNG, 100);
-
- mGraphicBuffer->unlock();
- return result;
-}
-
-/* Generates a buffer that holds the expected result of compositing all of our
- * layers */
-int Hwc2TestExpectedBuffer::generateExpectedBuffer(
- const Hwc2TestLayers* testLayers,
- const std::vector<hwc2_layer_t>* allLayers,
- const std::set<hwc2_layer_t>* clearLayers)
-{
- mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
- mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
- "hwc2_test_buffer");
-
- int ret = mGraphicBuffer->initCheck();
- if (ret)
- return ret;
-
- if (!mGraphicBuffer->handle)
- return -EINVAL;
-
- const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(),
- allLayers->end());
-
- compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers,
- &allLayerSet, clearLayers);
-
- return 0;
-}
-
-int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle,
- int32_t* outFence)
-{
- if (mBufferArea.width == -1 || mBufferArea.height == -1)
- return -EINVAL;
-
- mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
- mFormat, BufferUsage::CPU_READ_OFTEN |
- BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer");
-
- int ret = mGraphicBuffer->initCheck();
- if (ret)
- return ret;
-
- if (!mGraphicBuffer->handle)
- return -EINVAL;
-
- *outFence = -1;
- *outHandle = mGraphicBuffer->handle;
-
- return 0;
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
deleted file mode 100644
index fd54fef..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_BUFFER_H
-#define _HWC2_TEST_BUFFER_H
-
-#include <android-base/unique_fd.h>
-#include <set>
-
-#include <hardware/hwcomposer2.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include "Hwc2TestProperties.h"
-
-class Hwc2TestFenceGenerator;
-class Hwc2TestLayers;
-
-class Hwc2TestBuffer {
-public:
- Hwc2TestBuffer();
- ~Hwc2TestBuffer();
-
- void updateBufferArea(const Area& bufferArea);
-
- int get(buffer_handle_t* outHandle, int32_t* outFence);
-
-protected:
- int generateBuffer();
-
- android::sp<android::GraphicBuffer> mGraphicBuffer;
-
- std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
-
- Area mBufferArea = {-1, -1};
- const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-
- bool mValidBuffer = false;
- buffer_handle_t mHandle = nullptr;
-};
-
-
-class Hwc2TestClientTargetBuffer {
-public:
- Hwc2TestClientTargetBuffer();
- ~Hwc2TestClientTargetBuffer();
-
- int get(buffer_handle_t* outHandle, int32_t* outFence,
- const Area& bufferArea, const Hwc2TestLayers* testLayers,
- const std::set<hwc2_layer_t>* clientLayers,
- const std::set<hwc2_layer_t>* clearLayers);
-
-protected:
- android::sp<android::GraphicBuffer> mGraphicBuffer;
-
- std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
-
- const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-};
-
-
-class Hwc2TestVirtualBuffer {
-public:
- void updateBufferArea(const Area& bufferArea);
-
- bool writeBufferToFile(std::string path);
-
- android::sp<android::GraphicBuffer>& graphicBuffer()
- {
- return mGraphicBuffer;
- }
-
-protected:
- android::sp<android::GraphicBuffer> mGraphicBuffer;
-
- Area mBufferArea = {-1, -1};
-
- const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-};
-
-
-class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer {
-public:
- int generateExpectedBuffer(const Hwc2TestLayers* testLayers,
- const std::vector<hwc2_layer_t>* allLayers,
- const std::set<hwc2_layer_t>* clearLayers);
-};
-
-
-class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer {
-public:
- int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence);
-};
-
-#endif /* ifndef _HWC2_TEST_BUFFER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
deleted file mode 100644
index 14c60a7..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-
-#include <ui/Rect.h>
-
-#include "Hwc2TestClientTarget.h"
-
-int Hwc2TestClientTarget::getBuffer(const Hwc2TestLayers& testLayers,
- const std::set<hwc2_layer_t>& clientLayers,
- const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
- const Area& displayArea, buffer_handle_t* outHandle,
- int32_t* outAcquireFence)
-{
- if (!flipClientTarget) {
- bool needsClientTarget = false;
-
- for (auto clientLayer : clientLayers) {
- if (testLayers.getVisibleRegion(clientLayer).numRects > 0) {
- needsClientTarget = true;
- break;
- }
- }
-
- if (!needsClientTarget) {
- *outHandle = nullptr;
- *outAcquireFence = -1;
- return 0;
- }
- }
-
- return mBuffer.get(outHandle, outAcquireFence, displayArea,
- &testLayers, &clientLayers, &clearLayers);
-}
-
-
-Hwc2TestClientTargetSupport::Hwc2TestClientTargetSupport(
- Hwc2TestCoverage coverage, const Area& displayArea)
- : mBufferArea(coverage, displayArea),
- mDataspace(coverage),
- mSurfaceDamage(coverage)
-{
- mBufferArea.setDependent(&mSurfaceDamage);
-}
-
-std::string Hwc2TestClientTargetSupport::dump() const
-{
- std::stringstream dmp;
-
- dmp << "client target: \n";
-
- for (auto property : properties) {
- dmp << property->dump();
- }
-
- return dmp.str();
-}
-
-void Hwc2TestClientTargetSupport::reset()
-{
- for (auto property : properties) {
- property->reset();
- }
-}
-
-bool Hwc2TestClientTargetSupport::advance()
-{
- for (auto property : properties) {
- if (property->advance())
- return true;
- }
- return false;
-}
-
-Area Hwc2TestClientTargetSupport::getBufferArea() const
-{
- return mBufferArea.get();
-}
-
-android::ui::Dataspace Hwc2TestClientTargetSupport::getDataspace() const
-{
- return mDataspace.get();
-}
-
-const hwc_region_t Hwc2TestClientTargetSupport::getSurfaceDamage() const
-{
- return mSurfaceDamage.get();
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
deleted file mode 100644
index 6f4090f..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_CLIENT_TARGET_H
-#define _HWC2_TEST_CLIENT_TARGET_H
-
-#include <set>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestProperties.h"
-#include "Hwc2TestLayers.h"
-
-/* Generates client target buffers from client composition layers */
-class Hwc2TestClientTarget {
-public:
- int getBuffer(const Hwc2TestLayers& layers,
- const std::set<hwc2_layer_t>& clientLayers,
- const std::set<hwc2_layer_t>& clearLayers,
- bool clearClientTarget, const Area& displayArea,
- buffer_handle_t* outHandle, int32_t* outAcquireFence);
-
-private:
- Hwc2TestClientTargetBuffer mBuffer;
-};
-
-/* Generates valid client targets to test which ones the device will support */
-class Hwc2TestClientTargetSupport {
-public:
- Hwc2TestClientTargetSupport(Hwc2TestCoverage coverage,
- const Area& displayArea);
-
- std::string dump() const;
-
- void reset();
- bool advance();
-
- Area getBufferArea() const;
- android::ui::Dataspace getDataspace() const;
- const hwc_region_t getSurfaceDamage() const;
-
-private:
- std::array<Hwc2TestContainer*, 3> properties = {{
- &mDataspace, &mSurfaceDamage, &mBufferArea
- }};
-
- Hwc2TestBufferArea mBufferArea;
- Hwc2TestDataspace mDataspace;
- Hwc2TestSurfaceDamage mSurfaceDamage;
-};
-
-#endif /* ifndef _HWC2_TEST_CLIENT_TARGET_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
deleted file mode 100644
index c1c9cc8..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-
-#include "Hwc2TestLayer.h"
-
-Hwc2TestCoverage getCoverage(Hwc2TestPropertyName property,
- Hwc2TestCoverage coverage, const std::unordered_map<Hwc2TestPropertyName,
- Hwc2TestCoverage>& coverageExceptions) {
- auto exception = coverageExceptions.find(property);
- return (exception != coverageExceptions.end())? exception->second : coverage;
-}
-
-Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage,
- const Area& displayArea)
- : Hwc2TestLayer(coverage, displayArea,
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { }
-
-Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage,
- const Area& displayArea, const std::unordered_map<Hwc2TestPropertyName,
- Hwc2TestCoverage>& coverageExceptions)
- : mBlendMode(getCoverage(Hwc2TestPropertyName::BlendMode, coverage,
- coverageExceptions)),
- mBufferArea(getCoverage(Hwc2TestPropertyName::BufferArea, coverage,
- coverageExceptions), displayArea),
- mColor(getCoverage(Hwc2TestPropertyName::Color, coverage,
- coverageExceptions)),
- mComposition(getCoverage(Hwc2TestPropertyName::Composition, coverage,
- coverageExceptions)),
- mDataspace(getCoverage(Hwc2TestPropertyName::Dataspace, coverage,
- coverageExceptions)),
- mDisplayFrame(getCoverage(Hwc2TestPropertyName::DisplayFrame, coverage,
- coverageExceptions), displayArea),
- mPlaneAlpha(getCoverage(Hwc2TestPropertyName::PlaneAlpha, coverage,
- coverageExceptions)),
- mSourceCrop(getCoverage(Hwc2TestPropertyName::SourceCrop, coverage,
- coverageExceptions)),
- mSurfaceDamage(getCoverage(Hwc2TestPropertyName::SurfaceDamage, coverage,
- coverageExceptions)),
- mTransform(getCoverage(Hwc2TestPropertyName::Transform, coverage,
- coverageExceptions))
-{
- mBufferArea.setDependent(&mBuffer);
- mBufferArea.setDependent(&mSourceCrop);
- mBufferArea.setDependent(&mSurfaceDamage);
- mBlendMode.setDependent(&mColor);
-}
-
-std::string Hwc2TestLayer::dump() const
-{
- std::stringstream dmp;
-
- dmp << "layer: \n";
-
- for (auto property : mProperties) {
- dmp << property->dump();
- }
-
- dmp << mVisibleRegion.dump();
- dmp << "\tz order: " << mZOrder << "\n";
-
- return dmp.str();
-}
-
-int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle,
- android::base::unique_fd* outAcquireFence)
-{
- int32_t acquireFence;
- int ret = mBuffer.get(outHandle, &acquireFence);
- outAcquireFence->reset(acquireFence);
- return ret;
-}
-
-int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle,
- int32_t* outAcquireFence)
-{
- return mBuffer.get(outHandle, outAcquireFence);
-}
-
-void Hwc2TestLayer::setZOrder(uint32_t zOrder)
-{
- mZOrder = zOrder;
-}
-
-void Hwc2TestLayer::setVisibleRegion(const android::Region& region)
-{
- return mVisibleRegion.set(region);
-}
-
-void Hwc2TestLayer::reset()
-{
- mVisibleRegion.release();
-
- for (auto property : mProperties) {
- property->reset();
- }
-}
-
-bool Hwc2TestLayer::advance()
-{
- for (auto property : mProperties) {
- if (property->isSupported(mComposition.get()))
- if (property->advance())
- return true;
- }
- return false;
-}
-
-hwc2_blend_mode_t Hwc2TestLayer::getBlendMode() const
-{
- return mBlendMode.get();
-}
-
-Area Hwc2TestLayer::getBufferArea() const
-{
- return mBufferArea.get();
-}
-
-hwc_color_t Hwc2TestLayer::getColor() const
-{
- return mColor.get();
-}
-
-hwc2_composition_t Hwc2TestLayer::getComposition() const
-{
- return mComposition.get();
-}
-
-/* The cursor position corresponds to {displayFrame.left, displayFrame.top} */
-hwc_rect_t Hwc2TestLayer::getCursorPosition() const
-{
- return mDisplayFrame.get();
-}
-
-android::ui::Dataspace Hwc2TestLayer::getDataspace() const
-{
- return mDataspace.get();
-}
-
-hwc_rect_t Hwc2TestLayer::getDisplayFrame() const
-{
- return mDisplayFrame.get();
-}
-
-float Hwc2TestLayer::getPlaneAlpha() const
-{
- return mPlaneAlpha.get();
-}
-
-hwc_frect_t Hwc2TestLayer::getSourceCrop() const
-{
- return mSourceCrop.get();
-}
-
-hwc_region_t Hwc2TestLayer::getSurfaceDamage() const
-{
- return mSurfaceDamage.get();
-}
-
-hwc_transform_t Hwc2TestLayer::getTransform() const
-{
- return mTransform.get();
-}
-
-hwc_region_t Hwc2TestLayer::getVisibleRegion() const
-{
- return mVisibleRegion.get();
-}
-
-uint32_t Hwc2TestLayer::getZOrder() const
-{
- return mZOrder;
-}
-
-bool Hwc2TestLayer::advanceBlendMode()
-{
- return mBlendMode.advance();
-}
-
-bool Hwc2TestLayer::advanceBufferArea()
-{
- return mBufferArea.advance();
-}
-
-bool Hwc2TestLayer::advanceColor()
-{
- return mColor.advance();
-}
-
-bool Hwc2TestLayer::advanceComposition()
-{
- return mComposition.advance();
-}
-
-bool Hwc2TestLayer::advanceCursorPosition()
-{
- return mDisplayFrame.advance();
-}
-
-bool Hwc2TestLayer::advanceDataspace()
-{
- return mDataspace.advance();
-}
-
-bool Hwc2TestLayer::advanceDisplayFrame()
-{
- return mDisplayFrame.advance();
-}
-
-bool Hwc2TestLayer::advancePlaneAlpha()
-{
- return mPlaneAlpha.advance();
-}
-
-bool Hwc2TestLayer::advanceSourceCrop()
-{
- return mSourceCrop.advance();
-}
-
-bool Hwc2TestLayer::advanceSurfaceDamage()
-{
- return mSurfaceDamage.advance();
-}
-
-bool Hwc2TestLayer::advanceTransform()
-{
- return mTransform.advance();
-}
-
-bool Hwc2TestLayer::advanceVisibleRegion()
-{
- if (mPlaneAlpha.advance())
- return true;
- return mDisplayFrame.advance();
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
deleted file mode 100644
index 29ae521..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_LAYER_H
-#define _HWC2_TEST_LAYER_H
-
-#include <android-base/unique_fd.h>
-#include <unordered_map>
-
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestProperties.h"
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-class Hwc2TestLayer {
-public:
- Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea);
-
- Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea,
- const std::unordered_map<Hwc2TestPropertyName,
- Hwc2TestCoverage>& coverage_exceptions);
-
- std::string dump() const;
-
- int getBuffer(buffer_handle_t* outHandle,
- android::base::unique_fd* outAcquireFence);
- int getBuffer(buffer_handle_t* outHandle, int32_t* outAcquireFence);
-
- void setZOrder(uint32_t zOrder);
- void setVisibleRegion(const android::Region& region);
-
- void reset();
- bool advance();
-
- hwc2_blend_mode_t getBlendMode() const;
- Area getBufferArea() const;
- hwc_color_t getColor() const;
- hwc2_composition_t getComposition() const;
- hwc_rect_t getCursorPosition() const;
- android::ui::Dataspace getDataspace() const;
- hwc_rect_t getDisplayFrame() const;
- float getPlaneAlpha() const;
- hwc_frect_t getSourceCrop() const;
- hwc_region_t getSurfaceDamage() const;
- hwc_transform_t getTransform() const;
- hwc_region_t getVisibleRegion() const;
- uint32_t getZOrder() const;
-
- bool advanceBlendMode();
- bool advanceBufferArea();
- bool advanceColor();
- bool advanceComposition();
- bool advanceCursorPosition();
- bool advanceDataspace();
- bool advanceDisplayFrame();
- bool advancePlaneAlpha();
- bool advanceSourceCrop();
- bool advanceSurfaceDamage();
- bool advanceTransform();
- bool advanceVisibleRegion();
-
-private:
- std::array<Hwc2TestContainer*, 10> mProperties = {{
- &mTransform, &mColor, &mDataspace, &mPlaneAlpha, &mSourceCrop,
- &mSurfaceDamage, &mBlendMode, &mBufferArea, &mDisplayFrame,
- &mComposition
- }};
-
- Hwc2TestBuffer mBuffer;
-
- Hwc2TestBlendMode mBlendMode;
- Hwc2TestBufferArea mBufferArea;
- Hwc2TestColor mColor;
- Hwc2TestComposition mComposition;
- Hwc2TestDataspace mDataspace;
- Hwc2TestDisplayFrame mDisplayFrame;
- Hwc2TestPlaneAlpha mPlaneAlpha;
- Hwc2TestSourceCrop mSourceCrop;
- Hwc2TestSurfaceDamage mSurfaceDamage;
- Hwc2TestTransform mTransform;
- Hwc2TestVisibleRegion mVisibleRegion;
-
- uint32_t mZOrder = UINT32_MAX;
-};
-
-#endif /* ifndef _HWC2_TEST_LAYER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
deleted file mode 100644
index 90127a1..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/* * Copyright (C) 2016 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 <sstream>
-#include <gtest/gtest.h>
-
-#include "Hwc2TestLayers.h"
-
-Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
- Hwc2TestCoverage coverage, const Area& displayArea)
- : Hwc2TestLayers(layers, coverage, displayArea,
- std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { }
-
-Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
- Hwc2TestCoverage coverage, const Area& displayArea,
- const std::unordered_map<Hwc2TestPropertyName,
- Hwc2TestCoverage>& coverageExceptions)
- : mDisplayArea(displayArea)
-{
- for (auto layer : layers) {
- mTestLayers.emplace(std::piecewise_construct,
- std::forward_as_tuple(layer),
- std::forward_as_tuple(coverage, displayArea, coverageExceptions));
- }
-
- /* Iterate over the layers in order and assign z orders in the same order.
- * This allows us to iterate over z orders in the same way when computing
- * visible regions */
- uint32_t nextZOrder = layers.size();
-
- for (auto& testLayer : mTestLayers) {
- testLayer.second.setZOrder(nextZOrder--);
- }
-
- setVisibleRegions();
-}
-
-std::string Hwc2TestLayers::dump() const
-{
- std::stringstream dmp;
- for (auto& testLayer : mTestLayers) {
- dmp << testLayer.second.dump();
- }
- return dmp.str();
-}
-
-void Hwc2TestLayers::reset()
-{
- for (auto& testLayer : mTestLayers) {
- testLayer.second.reset();
- }
-
- setVisibleRegions();
-}
-
-bool Hwc2TestLayers::advance()
-{
- auto itr = mTestLayers.begin();
- bool optimized;
-
- while (itr != mTestLayers.end()) {
- if (itr->second.advance()) {
- optimized = setVisibleRegions();
- if (!mOptimize || optimized)
- return true;
- itr = mTestLayers.begin();
- } else {
- itr->second.reset();
- ++itr;
- }
- }
- return false;
-}
-
-bool Hwc2TestLayers::advanceVisibleRegions()
-{
- auto itr = mTestLayers.begin();
- bool optimized;
-
- while (itr != mTestLayers.end()) {
- if (itr->second.advanceVisibleRegion()) {
- optimized = setVisibleRegions();
- if (!mOptimize || optimized)
- return true;
- itr = mTestLayers.begin();
- } else {
- itr->second.reset();
- ++itr;
- }
- }
- return false;
-}
-
-/* Removes layouts that do not cover the entire display.
- * Also removes layouts where a layer is completely blocked from view.
- */
-bool Hwc2TestLayers::optimizeLayouts()
-{
- mOptimize = true;
-
- if (setVisibleRegions())
- return true;
- return advance();
-}
-
-bool Hwc2TestLayers::contains(hwc2_layer_t layer) const
-{
- return mTestLayers.count(layer) != 0;
-}
-
-int Hwc2TestLayers::getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle,
- int32_t* outAcquireFence)
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getBuffer(outHandle, outAcquireFence);
-}
-
-hwc2_blend_mode_t Hwc2TestLayers::getBlendMode(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getBlendMode();
-}
-
-Area Hwc2TestLayers::getBufferArea(hwc2_layer_t layer) const
-{
- auto testLayer = mTestLayers.find(layer);
- if (testLayer == mTestLayers.end())
- [] () { GTEST_FAIL(); }();
- return testLayer->second.getBufferArea();
-}
-
-hwc_color_t Hwc2TestLayers::getColor(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getColor();
-}
-
-hwc2_composition_t Hwc2TestLayers::getComposition(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getComposition();
-}
-
-hwc_rect_t Hwc2TestLayers::getCursorPosition(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getCursorPosition();
-}
-
-android::ui::Dataspace Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getDataspace();
-}
-
-hwc_rect_t Hwc2TestLayers::getDisplayFrame(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getDisplayFrame();
-}
-
-float Hwc2TestLayers::getPlaneAlpha(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getPlaneAlpha();
-}
-
-hwc_frect_t Hwc2TestLayers::getSourceCrop(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getSourceCrop();
-}
-
-hwc_region_t Hwc2TestLayers::getSurfaceDamage(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getSurfaceDamage();
-}
-
-hwc_transform_t Hwc2TestLayers::getTransform(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getTransform();
-}
-
-hwc_region_t Hwc2TestLayers::getVisibleRegion(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getVisibleRegion();
-}
-
-uint32_t Hwc2TestLayers::getZOrder(hwc2_layer_t layer) const
-{
- if (mTestLayers.count(layer) == 0) {
- []() { GTEST_FAIL(); }();
- }
- return mTestLayers.at(layer).getZOrder();
-}
-
-/* Sets the visible regions for a display. Returns false if the layers do not
- * cover the entire display or if a layer is not visible */
-bool Hwc2TestLayers::setVisibleRegions()
-{
- /* The region of the display that is covered by layers above the current
- * layer */
- android::Region aboveOpaqueLayers;
-
- bool optimized = true;
-
- /* Iterate over test layers from max z order to min z order. */
- for (auto& testLayer : mTestLayers) {
- android::Region visibleRegion;
-
- /* Set the visible region of this layer */
- const hwc_rect_t displayFrame = testLayer.second.getDisplayFrame();
-
- visibleRegion.set(android::Rect(displayFrame.left, displayFrame.top,
- displayFrame.right, displayFrame.bottom));
-
- /* Remove the area covered by opaque layers above this layer
- * from this layer's visible region */
- visibleRegion.subtractSelf(aboveOpaqueLayers);
-
- testLayer.second.setVisibleRegion(visibleRegion);
-
- /* If a layer is not visible, return false */
- if (visibleRegion.isEmpty())
- optimized = false;
-
- /* If this layer is opaque, store the region it covers */
- if (testLayer.second.getPlaneAlpha() == 1.0f)
- aboveOpaqueLayers.orSelf(visibleRegion);
- }
-
- /* If the opaque region does not cover the entire display return false */
- if (!aboveOpaqueLayers.isRect())
- return false;
-
- const auto rect = aboveOpaqueLayers.begin();
- if (rect->left != 0 || rect->top != 0 || rect->right != mDisplayArea.width
- || rect->bottom != mDisplayArea.height)
- return false;
-
- return optimized;
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
deleted file mode 100644
index 909dd48..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_LAYERS_H
-#define _HWC2_TEST_LAYERS_H
-
-#include <map>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestProperties.h"
-#include "Hwc2TestLayer.h"
-
-class Hwc2TestLayers {
-public:
- Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
- Hwc2TestCoverage coverage, const Area& displayArea);
-
- Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
- Hwc2TestCoverage coverage, const Area& displayArea,
- const std::unordered_map<Hwc2TestPropertyName,
- Hwc2TestCoverage>& coverageExceptions);
-
- std::string dump() const;
-
- void reset();
-
- bool advance();
- bool advanceVisibleRegions();
-
- /* Test cases with multiple layers and property values can take quite some
- * time to run. A significant amount of time can be spent on test cases
- * where one layer is changing property values but is not visible. To
- * decrease runtime, this function can be called. Removes layouts where a
- * layer is completely blocked from view. It also removes layouts that do
- * not cover the entire display.*/
- bool optimizeLayouts();
-
- bool contains(hwc2_layer_t layer) const;
-
- int getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle,
- int32_t* outAcquireFence);
-
- hwc2_blend_mode_t getBlendMode(hwc2_layer_t layer) const;
- Area getBufferArea(hwc2_layer_t layer) const;
- hwc_color_t getColor(hwc2_layer_t layer) const;
- hwc2_composition_t getComposition(hwc2_layer_t layer) const;
- hwc_rect_t getCursorPosition(hwc2_layer_t layer) const;
- android::ui::Dataspace getDataspace(hwc2_layer_t layer) const;
- hwc_rect_t getDisplayFrame(hwc2_layer_t layer) const;
- android_pixel_format_t getFormat(hwc2_layer_t layer) const;
- float getPlaneAlpha(hwc2_layer_t layer) const;
- hwc_frect_t getSourceCrop(hwc2_layer_t layer) const;
- hwc_region_t getSurfaceDamage(hwc2_layer_t layer) const;
- hwc_transform_t getTransform(hwc2_layer_t layer) const;
- hwc_region_t getVisibleRegion(hwc2_layer_t layer) const;
- uint32_t getZOrder(hwc2_layer_t layer) const;
-
-private:
- bool setVisibleRegions();
-
- std::map<hwc2_layer_t, Hwc2TestLayer> mTestLayers;
-
- Area mDisplayArea;
-
- bool mOptimize = false;
-};
-
-#endif /* ifndef _HWC2_TEST_LAYERS_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
deleted file mode 100644
index 904b927..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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.
- */
-
-#include <sstream>
-#include <android/hardware/graphics/common/1.0/types.h>
-
-#include "Hwc2TestPixelComparator.h"
-
-using android::hardware::graphics::common::V1_0::BufferUsage;
-
-uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride,
- uint8_t* img) const
-{
- uint32_t r = img[(y * stride + x) * 4 + 0];
- uint32_t g = img[(y * stride + x) * 4 + 1];
- uint32_t b = img[(y * stride + x) * 4 + 2];
- uint32_t a = img[(y * stride + x) * 4 + 3];
-
- uint32_t pixel = 0;
- pixel |= r;
- pixel |= g << 8;
- pixel |= b << 16;
- pixel |= a << 24;
- return pixel;
-}
-
-void ComparatorResult::CompareBuffers(
- android::sp<android::GraphicBuffer>& resultBuffer,
- android::sp<android::GraphicBuffer>& expectedBuffer)
-{
- uint8_t* resultBufferImg;
- uint8_t* expectedBufferImg;
- resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
- (void**)(&resultBufferImg));
-
- expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
- (void**)(&expectedBufferImg));
- mComparisons.clear();
- int32_t mDifferentPixelCount = 0;
- int32_t mBlankPixelCount = 0;
-
- for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) {
- for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) {
- uint32_t result = getPixel(x, y, resultBuffer->getStride(),
- resultBufferImg);
- uint32_t expected = getPixel(x, y, expectedBuffer->getStride(),
- expectedBufferImg);
-
- if (result == 0)
- mBlankPixelCount++;
-
- if (result != expected)
- mDifferentPixelCount++;
-
- mComparisons.emplace_back(std::make_tuple(x, y, result, expected));
- }
- }
- resultBuffer->unlock();
- expectedBuffer->unlock();
-}
-
-std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y,
- uint32_t resultPixel, uint32_t expectedPixel) const
-{
- uint32_t resultAlpha = (resultPixel >> 24) & 0xFF;
- uint32_t resultBlue = (resultPixel >> 16) & 0xFF;
- uint32_t resultGreen = (resultPixel >> 8) & 0xFF;
- uint32_t resultRed = resultPixel & 0xFF;
-
- uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF;
- uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF;
- uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF;
- uint32_t expectedRed = expectedPixel & 0xFF;
-
- std::ostringstream stream;
-
- stream << "x: " << x << " y: " << y << std::endl;
- stream << std::hex;
- stream << "Result pixel: " << resultRed << "|" << resultGreen << "|"
- << resultBlue << "|" << resultAlpha << std::endl;
-
- stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|"
- << expectedBlue << "|" << expectedAlpha << std::endl;
-
- return stream.str();
-}
-
-std::string ComparatorResult::dumpComparison() const
-{
- std::ostringstream stream;
- stream << "Number of different pixels: " << mDifferentPixelCount;
-
- for (const auto& comparison : mComparisons) {
- if (std::get<2>(comparison) != std::get<3>(comparison))
- stream << pixelDiff(std::get<0>(comparison),
- std::get<1>(comparison), std::get<2>(comparison),
- std::get<3>(comparison));
- }
- return stream.str();
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
deleted file mode 100644
index 55fa936..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- */
-#ifndef _HWC2_TEST_PIXEL_COMPARATOR_H
-#define _HWC2_TEST_PIXEL_COMPARATOR_H
-
-#include <ui/GraphicBuffer.h>
-#include <cstdint>
-#include <string>
-#include <utility>
-#include <vector>
-
-class ComparatorResult {
-public:
- static ComparatorResult& get()
- {
- static ComparatorResult instance;
- return instance;
- }
-
- void CompareBuffers(android::sp<android::GraphicBuffer>& resultBuffer,
- android::sp<android::GraphicBuffer>& expectedBuffer);
-
- std::string dumpComparison() const;
-
- ComparatorResult(const ComparatorResult&) = delete;
- ComparatorResult(ComparatorResult&&) = delete;
- ComparatorResult& operator=(ComparatorResult const&) = delete;
- ComparatorResult& operator=(ComparatorResult&&) = delete;
-
- int32_t getDifferentPixelCount() const { return mDifferentPixelCount; }
- int32_t getBlankPixelCount() const { return mBlankPixelCount; }
-
-private:
- ComparatorResult() = default;
- uint32_t getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const;
- std::string pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel,
- uint32_t expectedPixel) const;
-
- int32_t mDifferentPixelCount;
- int32_t mBlankPixelCount;
- /* std::tuple<X coordinate, Y coordinate, resultPixel, expectedPixel> */
- std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>>
- mComparisons;
-};
-
-#endif /* ifndef _HWC2_TEST_PIXEL_COMPARATOR_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
deleted file mode 100644
index c5b92d0..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-#include <cutils/log.h>
-#include <ui/Rect.h>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestProperties.h"
-
-Hwc2TestBufferArea::Hwc2TestBufferArea(Hwc2TestCoverage coverage,
- const Area& displayArea)
- : Hwc2TestProperty(mBufferAreas, mCompositionSupport),
- mScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteScalars:
- (coverage == Hwc2TestCoverage::Basic)? mBasicScalars:
- mDefaultScalars),
- mDisplayArea(displayArea)
-{
- update();
-}
-
-std::string Hwc2TestBufferArea::dump() const
-{
- std::stringstream dmp;
- const Area& curr = get();
- dmp << "\tbuffer area: width " << curr.width << ", height " << curr.height
- << "\n";
- return dmp.str();
-}
-
-void Hwc2TestBufferArea::setDependent(Hwc2TestBuffer* buffer)
-{
- mBuffer = buffer;
- if (buffer) {
- buffer->updateBufferArea(get());
- }
-}
-
-void Hwc2TestBufferArea::setDependent(Hwc2TestSourceCrop* sourceCrop)
-{
- mSourceCrop = sourceCrop;
- if (mSourceCrop) {
- mSourceCrop->updateBufferArea(get());
- }
-}
-
-void Hwc2TestBufferArea::setDependent(Hwc2TestSurfaceDamage* surfaceDamage)
-{
- mSurfaceDamage = surfaceDamage;
- if (mSurfaceDamage) {
- mSurfaceDamage->updateBufferArea(get());
- }
-}
-
-void Hwc2TestBufferArea::update()
-{
- mBufferAreas.clear();
-
- if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
- mBufferAreas.push_back({0, 0});
- return;
- }
-
- for (auto scalar : mScalars) {
- mBufferAreas.push_back({static_cast<int32_t>(scalar * mDisplayArea.width),
- static_cast<int32_t>(scalar * mDisplayArea.height)});
- }
-
- updateDependents();
-}
-
-void Hwc2TestBufferArea::updateDependents()
-{
- const Area& curr = get();
-
- if (mBuffer)
- mBuffer->updateBufferArea(curr);
- if (mSourceCrop)
- mSourceCrop->updateBufferArea(curr);
- if (mSurfaceDamage)
- mSurfaceDamage->updateBufferArea(curr);
-}
-
-const std::vector<float> Hwc2TestBufferArea::mDefaultScalars = {
- 1.0f,
-};
-
-const std::vector<float> Hwc2TestBufferArea::mBasicScalars = {
- 1.0f, 0.5f,
-};
-
-const std::vector<float> Hwc2TestBufferArea::mCompleteScalars = {
- 1.0f, 0.75f, 0.5f
-};
-
-
-Hwc2TestBlendMode::Hwc2TestBlendMode(Hwc2TestCoverage coverage)
- : Hwc2TestProperty(coverage, mCompleteBlendModes, mBasicBlendModes,
- mDefaultBlendModes, mCompositionSupport) { }
-
-std::string Hwc2TestBlendMode::dump() const
-{
- std::stringstream dmp;
- dmp << "\tblend mode: " << getBlendModeName(get()) << "\n";
- return dmp.str();
-}
-
-void Hwc2TestBlendMode::setDependent(Hwc2TestColor* color)
-{
- mColor = color;
- updateDependents();
-}
-
-void Hwc2TestBlendMode::updateDependents()
-{
- if (mColor)
- mColor->updateBlendMode(get());
-}
-
-const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mDefaultBlendModes = {
- HWC2_BLEND_MODE_NONE,
-};
-
-const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mBasicBlendModes = {
- HWC2_BLEND_MODE_NONE,
- HWC2_BLEND_MODE_PREMULTIPLIED,
-};
-
-const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mCompleteBlendModes = {
- HWC2_BLEND_MODE_NONE,
- HWC2_BLEND_MODE_PREMULTIPLIED,
- HWC2_BLEND_MODE_COVERAGE,
-};
-
-
-Hwc2TestColor::Hwc2TestColor(Hwc2TestCoverage coverage,
- hwc2_blend_mode_t blendMode)
- : Hwc2TestProperty(mColors, mCompositionSupport),
- mBaseColors((coverage == Hwc2TestCoverage::Complete)? mCompleteBaseColors:
- (coverage == Hwc2TestCoverage::Basic)? mBasicBaseColors:
- mDefaultBaseColors),
- mBlendMode(blendMode)
-{
- update();
-}
-
-std::string Hwc2TestColor::dump() const
-{
- std::stringstream dmp;
- const hwc_color_t& color = get();
- dmp << "\tcolor: r " << std::to_string(color.r) << ", g "
- << std::to_string(color.g) << ", b " << std::to_string(color.b)
- << ", a " << std::to_string(color.a) << "\n";
- return dmp.str();
-}
-
-void Hwc2TestColor::updateBlendMode(hwc2_blend_mode_t blendMode)
-{
- mBlendMode = blendMode;
- update();
-}
-
-void Hwc2TestColor::update()
-{
- if (mBlendMode != HWC2_BLEND_MODE_PREMULTIPLIED) {
- mColors = mBaseColors;
- return;
- }
-
- mColors.clear();
-
- for (const hwc_color_t& baseColor : mBaseColors) {
- if (baseColor.a >= baseColor.r && baseColor.a >= baseColor.g
- && baseColor.a >= baseColor.b) {
- mColors.push_back(baseColor);
- }
- }
-
-}
-
-const std::vector<hwc_color_t> Hwc2TestColor::mDefaultBaseColors = {
- {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
-};
-
-const std::vector<hwc_color_t> Hwc2TestColor::mBasicBaseColors = {
- {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
- { 0, 0, 0, 0},
-};
-
-const std::vector<hwc_color_t> Hwc2TestColor::mCompleteBaseColors = {
- {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
- {UINT8_MAX, UINT8_MAX, UINT8_MAX, 0},
- {UINT8_MAX, UINT8_MAX, 0, UINT8_MAX},
- {UINT8_MAX, UINT8_MAX, 0, 0},
- {UINT8_MAX, 0, UINT8_MAX, UINT8_MAX},
- {UINT8_MAX, 0, UINT8_MAX, 0},
- {UINT8_MAX, 0, 0, UINT8_MAX},
- {UINT8_MAX, 0, 0, 0},
- { 0, UINT8_MAX, UINT8_MAX, UINT8_MAX},
- { 0, UINT8_MAX, UINT8_MAX, 0},
- { 0, UINT8_MAX, 0, UINT8_MAX},
- { 0, UINT8_MAX, 0, 0},
- { 0, 0, UINT8_MAX, UINT8_MAX},
- { 0, 0, UINT8_MAX, 0},
- { 0, 0, 0, UINT8_MAX},
- { 0, 0, 0, 0},
-};
-
-
-Hwc2TestComposition::Hwc2TestComposition(Hwc2TestCoverage coverage)
- : Hwc2TestProperty(coverage, mCompleteCompositions, mBasicCompositions,
- mDefaultCompositions, mCompositionSupport) { }
-
-std::string Hwc2TestComposition::dump() const
-{
- std::stringstream dmp;
- dmp << "\tcomposition: " << getCompositionName(get()) << "\n";
- return dmp.str();
-}
-
-const std::vector<hwc2_composition_t> Hwc2TestComposition::mDefaultCompositions = {
- HWC2_COMPOSITION_DEVICE,
-};
-
-const std::vector<hwc2_composition_t> Hwc2TestComposition::mBasicCompositions = {
- HWC2_COMPOSITION_CLIENT,
- HWC2_COMPOSITION_DEVICE,
-};
-
-const std::vector<hwc2_composition_t> Hwc2TestComposition::mCompleteCompositions = {
- HWC2_COMPOSITION_CLIENT,
- HWC2_COMPOSITION_DEVICE,
- HWC2_COMPOSITION_SOLID_COLOR,
- HWC2_COMPOSITION_CURSOR,
- HWC2_COMPOSITION_SIDEBAND,
-};
-
-
-Hwc2TestDataspace::Hwc2TestDataspace(Hwc2TestCoverage coverage)
- : Hwc2TestProperty(coverage, completeDataspaces, basicDataspaces,
- defaultDataspaces, mCompositionSupport) { }
-
-std::string Hwc2TestDataspace::dump() const
-{
- std::stringstream dmp;
- dmp << "\tdataspace: " << static_cast<int32_t>(get()) << "\n";
- return dmp.str();
-}
-
-const std::vector<android::ui::Dataspace> Hwc2TestDataspace::defaultDataspaces = {
- android::ui::Dataspace::UNKNOWN,
-};
-
-const std::vector<android::ui::Dataspace> Hwc2TestDataspace::basicDataspaces = {
- android::ui::Dataspace::UNKNOWN,
- android::ui::Dataspace::V0_SRGB,
-};
-
-const std::vector<android::ui::Dataspace> Hwc2TestDataspace::completeDataspaces = {
- android::ui::Dataspace::UNKNOWN,
- android::ui::Dataspace::ARBITRARY,
- android::ui::Dataspace::STANDARD_SHIFT,
- android::ui::Dataspace::STANDARD_MASK,
- android::ui::Dataspace::STANDARD_UNSPECIFIED,
- android::ui::Dataspace::STANDARD_BT709,
- android::ui::Dataspace::STANDARD_BT601_625,
- android::ui::Dataspace::STANDARD_BT601_625_UNADJUSTED,
- android::ui::Dataspace::STANDARD_BT601_525,
- android::ui::Dataspace::STANDARD_BT601_525_UNADJUSTED,
- android::ui::Dataspace::STANDARD_BT2020,
- android::ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE,
- android::ui::Dataspace::STANDARD_BT470M,
- android::ui::Dataspace::STANDARD_FILM,
- android::ui::Dataspace::TRANSFER_SHIFT,
- android::ui::Dataspace::TRANSFER_MASK,
- android::ui::Dataspace::TRANSFER_UNSPECIFIED,
- android::ui::Dataspace::TRANSFER_LINEAR,
- android::ui::Dataspace::TRANSFER_SRGB,
- android::ui::Dataspace::TRANSFER_SMPTE_170M,
- android::ui::Dataspace::TRANSFER_GAMMA2_2,
- android::ui::Dataspace::TRANSFER_GAMMA2_8,
- android::ui::Dataspace::TRANSFER_ST2084,
- android::ui::Dataspace::TRANSFER_HLG,
- android::ui::Dataspace::RANGE_SHIFT,
- android::ui::Dataspace::RANGE_MASK,
- android::ui::Dataspace::RANGE_UNSPECIFIED,
- android::ui::Dataspace::RANGE_FULL,
- android::ui::Dataspace::RANGE_LIMITED,
- android::ui::Dataspace::SRGB_LINEAR,
- android::ui::Dataspace::V0_SRGB_LINEAR,
- android::ui::Dataspace::SRGB,
- android::ui::Dataspace::V0_SRGB,
- android::ui::Dataspace::JFIF,
- android::ui::Dataspace::V0_JFIF,
- android::ui::Dataspace::BT601_625,
- android::ui::Dataspace::V0_BT601_625,
- android::ui::Dataspace::BT601_525,
- android::ui::Dataspace::V0_BT601_525,
- android::ui::Dataspace::BT709,
- android::ui::Dataspace::V0_BT709,
- android::ui::Dataspace::DEPTH,
-};
-
-
-Hwc2TestDisplayDimension::Hwc2TestDisplayDimension(Hwc2TestCoverage coverage)
- : Hwc2TestProperty(
- (coverage == Hwc2TestCoverage::Complete)? mCompleteDisplayDimensions:
- (coverage == Hwc2TestCoverage::Basic)? mBasicDisplayDimensions:
- mDefaultDisplayDimensions, mCompositionSupport) { }
-
-std::string Hwc2TestDisplayDimension::dump() const
-{
- std::stringstream dmp;
- const UnsignedArea& curr = get();
- dmp << "\tdisplay dimension: " << curr.width<< " x " << curr.height<< "\n";
- return dmp.str();
-}
-
-void Hwc2TestDisplayDimension::setDependent(Hwc2TestVirtualBuffer* buffer)
-{
- mBuffers.insert(buffer);
- updateDependents();
-}
-
-void Hwc2TestDisplayDimension::updateDependents()
-{
- const UnsignedArea& curr = get();
-
- for (Hwc2TestVirtualBuffer* buffer : mBuffers)
- buffer->updateBufferArea({static_cast<int32_t>(curr.width),
- static_cast<int32_t>(curr.height)});
-}
-
-const std::vector<UnsignedArea>
- Hwc2TestDisplayDimension::mDefaultDisplayDimensions = {
- {1920, 1080},
-};
-
-const std::vector<UnsignedArea>
- Hwc2TestDisplayDimension::mBasicDisplayDimensions = {
- {640, 480},
- {1280, 720},
- {1920, 1080},
- {1920, 1200},
-};
-
-const std::vector<UnsignedArea>
- Hwc2TestDisplayDimension::mCompleteDisplayDimensions = {
- {320, 240},
- {480, 320},
- {640, 480},
- {1280, 720},
- {1920, 1080},
- {1920, 1200},
- {2560, 1440},
- {2560, 1600},
- {3840, 2160},
- {4096, 2160},
-};
-
-
-Hwc2TestDisplayFrame::Hwc2TestDisplayFrame(Hwc2TestCoverage coverage,
- const Area& displayArea)
- : Hwc2TestProperty(mDisplayFrames, mCompositionSupport),
- mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
- (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
- mDefaultFrectScalars),
- mDisplayArea(displayArea)
-{
- update();
-}
-
-std::string Hwc2TestDisplayFrame::dump() const
-{
- std::stringstream dmp;
- const hwc_rect_t& displayFrame = get();
- dmp << "\tdisplay frame: left " << displayFrame.left << ", top "
- << displayFrame.top << ", right " << displayFrame.right
- << ", bottom " << displayFrame.bottom << "\n";
- return dmp.str();
-}
-
-void Hwc2TestDisplayFrame::update()
-{
- mDisplayFrames.clear();
-
- if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
- mDisplayFrames.push_back({0, 0, 0, 0});
- return;
- }
-
- for (const auto& frectScalar : mFrectScalars) {
- mDisplayFrames.push_back({
- static_cast<int>(frectScalar.left * mDisplayArea.width),
- static_cast<int>(frectScalar.top * mDisplayArea.height),
- static_cast<int>(frectScalar.right * mDisplayArea.width),
- static_cast<int>(frectScalar.bottom * mDisplayArea.height)});
- }
-}
-
-const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mDefaultFrectScalars = {
- {0.0, 0.0, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mBasicFrectScalars = {
- {0.0, 0.0, 1.0, 1.0},
- {0.0, 0.0, 1.0, 0.05},
- {0.0, 0.95, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mCompleteFrectScalars = {
- {0.0, 0.0, 1.0, 1.0},
- {0.0, 0.05, 1.0, 0.95},
- {0.0, 0.05, 1.0, 1.0},
- {0.0, 0.0, 1.0, 0.05},
- {0.0, 0.95, 1.0, 1.0},
- {0.25, 0.0, 0.75, 0.35},
- {0.25, 0.25, 0.75, 0.75},
-};
-
-
-Hwc2TestPlaneAlpha::Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage)
- : Hwc2TestProperty(coverage, mCompletePlaneAlphas, mBasicPlaneAlphas,
- mDefaultPlaneAlphas, mCompositionSupport) { }
-
-std::string Hwc2TestPlaneAlpha::dump() const
-{
- std::stringstream dmp;
- dmp << "\tplane alpha: " << get() << "\n";
- return dmp.str();
-}
-
-const std::vector<float> Hwc2TestPlaneAlpha::mDefaultPlaneAlphas = {
- 1.0f,
-};
-
-const std::vector<float> Hwc2TestPlaneAlpha::mBasicPlaneAlphas = {
- 1.0f, 0.0f,
-};
-
-const std::vector<float> Hwc2TestPlaneAlpha::mCompletePlaneAlphas = {
- 1.0f, 0.75f, 0.5f, 0.25f, 0.0f,
-};
-
-
-Hwc2TestSourceCrop::Hwc2TestSourceCrop(Hwc2TestCoverage coverage,
- const Area& bufferArea)
- : Hwc2TestProperty(mSourceCrops, mCompositionSupport),
- mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
- (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
- mDefaultFrectScalars),
- mBufferArea(bufferArea)
-{
- update();
-}
-
-std::string Hwc2TestSourceCrop::dump() const
-{
- std::stringstream dmp;
- const hwc_frect_t& sourceCrop = get();
- dmp << "\tsource crop: left " << sourceCrop.left << ", top "
- << sourceCrop.top << ", right " << sourceCrop.right << ", bottom "
- << sourceCrop.bottom << "\n";
- return dmp.str();
-}
-
-void Hwc2TestSourceCrop::updateBufferArea(const Area& bufferArea)
-{
- mBufferArea = bufferArea;
- update();
-}
-
-void Hwc2TestSourceCrop::update()
-{
- mSourceCrops.clear();
-
- if (mBufferArea.width == 0 && mBufferArea.height == 0) {
- mSourceCrops.push_back({0, 0, 0, 0});
- return;
- }
-
- for (const auto& frectScalar : mFrectScalars) {
- mSourceCrops.push_back({
- frectScalar.left * mBufferArea.width,
- frectScalar.top * mBufferArea.height,
- frectScalar.right * mBufferArea.width,
- frectScalar.bottom * mBufferArea.height});
- }
-}
-
-const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mDefaultFrectScalars = {
- {0.0, 0.0, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mBasicFrectScalars = {
- {0.0, 0.0, 1.0, 1.0},
- {0.0, 0.0, 0.5, 0.5},
- {0.5, 0.5, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mCompleteFrectScalars = {
- {0.0, 0.0, 1.0, 1.0},
- {0.0, 0.0, 0.5, 0.5},
- {0.5, 0.5, 1.0, 1.0},
- {0.0, 0.0, 0.25, 0.25},
- {0.25, 0.25, 0.75, 0.75},
-};
-
-
-Hwc2TestSurfaceDamage::Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage)
- : Hwc2TestProperty(mSurfaceDamages, mCompositionSupport),
- mRegionScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteRegionScalars:
- (coverage == Hwc2TestCoverage::Basic)? mBasicRegionScalars:
- mDefaultRegionScalars)
-{
- update();
-}
-
-Hwc2TestSurfaceDamage::~Hwc2TestSurfaceDamage()
-{
- freeSurfaceDamages();
-}
-
-std::string Hwc2TestSurfaceDamage::dump() const
-{
- std::stringstream dmp;
-
- const hwc_region_t& curr = get();
- dmp << "\tsurface damage: region count " << curr.numRects << "\n";
- for (size_t i = 0; i < curr.numRects; i++) {
- const hwc_rect_t& rect = curr.rects[i];
- dmp << "\t\trect: left " << rect.left << ", top " << rect.top
- << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
- }
-
- return dmp.str();
-}
-
-void Hwc2TestSurfaceDamage::updateBufferArea(const Area& bufferArea)
-{
- mBufferArea = bufferArea;
- update();
-}
-
-void Hwc2TestSurfaceDamage::update()
-{
- freeSurfaceDamages();
-
- if (mBufferArea.width == 0 && mBufferArea.height == 0) {
- mSurfaceDamages.push_back({0, nullptr});
- return;
- }
-
- hwc_region_t damage;
-
- for (const auto& regionScalar : mRegionScalars) {
- damage.numRects = regionScalar.size();
-
- if (damage.numRects > 0) {
- hwc_rect_t* rects = new hwc_rect_t[damage.numRects];
- if (!rects) {
- ALOGW("failed to allocate new hwc_rect_t array");
- continue;
- }
-
- for (size_t i = 0; i < damage.numRects; i++) {
- rects[i].left = regionScalar[i].left * mBufferArea.width;
- rects[i].top = regionScalar[i].top * mBufferArea.height;
- rects[i].right = regionScalar[i].right * mBufferArea.width;
- rects[i].bottom = regionScalar[i].bottom * mBufferArea.height;
- }
-
- damage.rects = static_cast<hwc_rect_t const*>(rects);
- } else {
- damage.rects = nullptr;
- }
-
- mSurfaceDamages.push_back(damage);
- }
-}
-
-void Hwc2TestSurfaceDamage::freeSurfaceDamages()
-{
- for (const auto& surfaceDamage : mSurfaceDamages) {
- if (surfaceDamage.numRects > 0 && surfaceDamage.rects)
- delete[] surfaceDamage.rects;
- }
- mSurfaceDamages.clear();
-}
-
-const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mDefaultRegionScalars = {
- {{}},
-};
-
-const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mBasicRegionScalars = {
- {{}},
- {{0.0, 0.0, 1.0, 1.0}},
-};
-
-const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mCompleteRegionScalars = {
- {{}},
- {{0.0, 0.0, 1.0, 1.0}},
- {{0.0, 0.0, 0.5, 0.5}, {0.5, 0.5, 1.0, 1.0}},
-};
-
-
-Hwc2TestTransform::Hwc2TestTransform(Hwc2TestCoverage coverage)
- : Hwc2TestProperty(coverage, mCompleteTransforms, mBasicTransforms,
- mDefaultTransforms, mCompositionSupport) { }
-
-std::string Hwc2TestTransform::dump() const
-{
- std::stringstream dmp;
- dmp << "\ttransform: " << getTransformName(get()) << "\n";
- return dmp.str();
-}
-
-const std::vector<hwc_transform_t> Hwc2TestTransform::mDefaultTransforms = {
- static_cast<hwc_transform_t>(0),
-};
-
-const std::vector<hwc_transform_t> Hwc2TestTransform::mBasicTransforms = {
- static_cast<hwc_transform_t>(0),
- HWC_TRANSFORM_FLIP_H,
- HWC_TRANSFORM_FLIP_V,
- HWC_TRANSFORM_ROT_90,
-};
-
-const std::vector<hwc_transform_t> Hwc2TestTransform::mCompleteTransforms = {
- static_cast<hwc_transform_t>(0),
- HWC_TRANSFORM_FLIP_H,
- HWC_TRANSFORM_FLIP_V,
- HWC_TRANSFORM_ROT_90,
- HWC_TRANSFORM_ROT_180,
- HWC_TRANSFORM_ROT_270,
- HWC_TRANSFORM_FLIP_H_ROT_90,
- HWC_TRANSFORM_FLIP_V_ROT_90,
-};
-
-
-Hwc2TestVisibleRegion::~Hwc2TestVisibleRegion()
-{
- release();
-}
-
-std::string Hwc2TestVisibleRegion::dump() const
-{
- std::stringstream dmp;
-
- const hwc_region_t& curr = get();
- dmp << "\tvisible region: region count " << curr.numRects << "\n";
- for (size_t i = 0; i < curr.numRects; i++) {
- const hwc_rect_t& rect = curr.rects[i];
- dmp << "\t\trect: left " << rect.left << ", top " << rect.top
- << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
- }
-
- return dmp.str();
-}
-
-void Hwc2TestVisibleRegion::set(const android::Region& visibleRegion)
-{
- release();
-
- size_t size = 0;
- const android::Rect* rects = visibleRegion.getArray(&size);
-
- mVisibleRegion.numRects = size;
- mVisibleRegion.rects = nullptr;
-
- if (size > 0) {
- hwc_rect_t* hwcRects = new hwc_rect_t[size];
- for (size_t i = 0; i < size; i++) {
- hwcRects[i].left = rects[i].left;
- hwcRects[i].top = rects[i].top;
- hwcRects[i].right = rects[i].right;
- hwcRects[i].bottom = rects[i].bottom;
- }
- mVisibleRegion.rects = hwcRects;
- }
-}
-
-hwc_region_t Hwc2TestVisibleRegion::get() const
-{
- return mVisibleRegion;
-}
-
-void Hwc2TestVisibleRegion::release()
-{
- if (mVisibleRegion.numRects > 0 && mVisibleRegion.rects)
- delete[] mVisibleRegion.rects;
- mVisibleRegion.rects = nullptr;
- mVisibleRegion.numRects = 0;
-}
-
-/* Identifies which layer properties are supported by each composition type.
- * hwc2_composition_t values range from:
- * HWC2_COMPOSITION_INVALID = 0,
- * HWC2_COMPOSITION_CLIENT = 1,
- * HWC2_COMPOSITION_DEVICE = 2,
- * HWC2_COMPOSITION_SOLID_COLOR = 3,
- * HWC2_COMPOSITION_CURSOR = 4,
- * HWC2_COMPOSITION_SIDEBAND = 5,
- *
- * Each property array can be indexed by a hwc2_composition_t value.
- * By using an array instead of a more complex data structure, runtimes for
- * some test cases showed a noticeable improvement.
- */
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestBufferArea::mCompositionSupport = {{
- false, true, true, false, true, true,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestBlendMode::mCompositionSupport = {{
- false, true, true, false, true, true,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestColor::mCompositionSupport = {{
- false, false, false, true, false, false,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestComposition::mCompositionSupport = {{
- false, true, true, true, true, true,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestDataspace::mCompositionSupport = {{
- false, true, true, true, true, false,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestDisplayDimension::mCompositionSupport = {{
- false, true, true, true, true, true,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestDisplayFrame::mCompositionSupport = {{
- false, true, true, true, false, true,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestPlaneAlpha::mCompositionSupport = {{
- false, true, true, true, true, true,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestSourceCrop::mCompositionSupport = {{
- false, true, true, false, true, false,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestSurfaceDamage::mCompositionSupport = {{
- false, false, true, false, true, false,
-}};
-
-/* INVALID CLIENT DEVICE COLOR CURSOR SIDEBAND */
-const std::array<bool, 6> Hwc2TestTransform::mCompositionSupport = {{
- false, true, true, false, true, true,
-}};
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
deleted file mode 100644
index 06ae314..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_PROPERTIES_H
-#define _HWC2_TEST_PROPERTIES_H
-
-#include <array>
-#include <vector>
-
-#include <ui/GraphicTypes.h>
-#include <ui/Region.h>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-enum class Hwc2TestCoverage {
- Default = 0,
- Basic,
- Complete,
-};
-
-enum class Hwc2TestPropertyName {
- BlendMode = 1,
- BufferArea,
- Color,
- Composition,
- CursorPosition,
- Dataspace,
- DisplayFrame,
- PlaneAlpha,
- SourceCrop,
- SurfaceDamage,
- Transform,
-};
-
-typedef struct {
- int32_t width;
- int32_t height;
-} Area;
-
-
-typedef struct {
- uint32_t width;
- uint32_t height;
-} UnsignedArea;
-
-
-class Hwc2TestContainer {
-public:
- virtual ~Hwc2TestContainer() = default;
-
- /* Resets the container */
- virtual void reset() = 0;
-
- /* Attempts to advance to the next valid value. Returns true if one can be
- * found */
- virtual bool advance() = 0;
-
- virtual std::string dump() const = 0;
-
- /* Returns true if the container supports the given composition type */
- virtual bool isSupported(hwc2_composition_t composition) = 0;
-};
-
-
-template <class T>
-class Hwc2TestProperty : public Hwc2TestContainer {
-public:
- Hwc2TestProperty(Hwc2TestCoverage coverage,
- const std::vector<T>& completeList, const std::vector<T>& basicList,
- const std::vector<T>& defaultList,
- const std::array<bool, 6>& compositionSupport)
- : Hwc2TestProperty((coverage == Hwc2TestCoverage::Complete)? completeList:
- (coverage == Hwc2TestCoverage::Basic)? basicList : defaultList,
- compositionSupport) { }
-
- Hwc2TestProperty(const std::vector<T>& list,
- const std::array<bool, 6>& compositionSupport)
- : mList(list),
- mCompositionSupport(compositionSupport) { }
-
- void reset() override
- {
- mListIdx = 0;
- }
-
- bool advance() override
- {
- if (mListIdx + 1 < mList.size()) {
- mListIdx++;
- updateDependents();
- return true;
- }
- reset();
- updateDependents();
- return false;
- }
-
- T get() const
- {
- return mList.at(mListIdx);
- }
-
- virtual bool isSupported(hwc2_composition_t composition)
- {
- return mCompositionSupport.at(composition);
- }
-
-protected:
- /* If a derived class has dependents, override this function */
- virtual void updateDependents() { }
-
- const std::vector<T>& mList;
- size_t mListIdx = 0;
-
- const std::array<bool, 6>& mCompositionSupport;
-};
-
-class Hwc2TestBuffer;
-class Hwc2TestSourceCrop;
-class Hwc2TestSurfaceDamage;
-
-class Hwc2TestBufferArea : public Hwc2TestProperty<Area> {
-public:
- Hwc2TestBufferArea(Hwc2TestCoverage coverage, const Area& displayArea);
-
- std::string dump() const override;
-
- void setDependent(Hwc2TestBuffer* buffer);
- void setDependent(Hwc2TestSourceCrop* sourceCrop);
- void setDependent(Hwc2TestSurfaceDamage* surfaceDamage);
-
-protected:
- void update();
- void updateDependents() override;
-
- const std::vector<float>& mScalars;
- static const std::vector<float> mDefaultScalars;
- static const std::vector<float> mBasicScalars;
- static const std::vector<float> mCompleteScalars;
-
- Area mDisplayArea;
-
- Hwc2TestBuffer* mBuffer = nullptr;
- Hwc2TestSourceCrop* mSourceCrop = nullptr;
- Hwc2TestSurfaceDamage* mSurfaceDamage = nullptr;
-
- std::vector<Area> mBufferAreas;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestColor;
-
-class Hwc2TestBlendMode : public Hwc2TestProperty<hwc2_blend_mode_t> {
-public:
- explicit Hwc2TestBlendMode(Hwc2TestCoverage coverage);
-
- std::string dump() const override;
-
- void setDependent(Hwc2TestColor* color);
-
-protected:
- void updateDependents() override;
-
- Hwc2TestColor* mColor = nullptr;
-
- static const std::vector<hwc2_blend_mode_t> mDefaultBlendModes;
- static const std::vector<hwc2_blend_mode_t> mBasicBlendModes;
- static const std::vector<hwc2_blend_mode_t> mCompleteBlendModes;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestColor : public Hwc2TestProperty<hwc_color_t> {
-public:
- explicit Hwc2TestColor(Hwc2TestCoverage coverage,
- hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE);
-
- std::string dump() const override;
-
- void updateBlendMode(hwc2_blend_mode_t blendMode);
-
-protected:
- void update();
-
- std::vector<hwc_color_t> mBaseColors;
- static const std::vector<hwc_color_t> mDefaultBaseColors;
- static const std::vector<hwc_color_t> mBasicBaseColors;
- static const std::vector<hwc_color_t> mCompleteBaseColors;
-
- hwc2_blend_mode_t mBlendMode;
-
- std::vector<hwc_color_t> mColors;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestComposition : public Hwc2TestProperty<hwc2_composition_t> {
-public:
- explicit Hwc2TestComposition(Hwc2TestCoverage coverage);
-
- std::string dump() const override;
-
-protected:
- static const std::vector<hwc2_composition_t> mDefaultCompositions;
- static const std::vector<hwc2_composition_t> mBasicCompositions;
- static const std::vector<hwc2_composition_t> mCompleteCompositions;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestDataspace : public Hwc2TestProperty<android::ui::Dataspace> {
-public:
- explicit Hwc2TestDataspace(Hwc2TestCoverage coverage);
-
- std::string dump() const override;
-
-protected:
- static const std::vector<android::ui::Dataspace> defaultDataspaces;
- static const std::vector<android::ui::Dataspace> basicDataspaces;
- static const std::vector<android::ui::Dataspace> completeDataspaces;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-class Hwc2TestVirtualBuffer;
-
-class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
-public:
- explicit Hwc2TestDisplayDimension(Hwc2TestCoverage coverage);
-
- std::string dump() const;
-
- void setDependent(Hwc2TestVirtualBuffer* buffer);
-
-private:
- void updateDependents();
-
- std::set<Hwc2TestVirtualBuffer*> mBuffers;
-
- static const std::vector<UnsignedArea> mDefaultDisplayDimensions;
- static const std::vector<UnsignedArea> mBasicDisplayDimensions;
- static const std::vector<UnsignedArea> mCompleteDisplayDimensions;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestDisplayFrame : public Hwc2TestProperty<hwc_rect_t> {
-public:
- Hwc2TestDisplayFrame(Hwc2TestCoverage coverage, const Area& displayArea);
-
- std::string dump() const override;
-
-protected:
- void update();
-
- const std::vector<hwc_frect_t>& mFrectScalars;
- const static std::vector<hwc_frect_t> mDefaultFrectScalars;
- const static std::vector<hwc_frect_t> mBasicFrectScalars;
- const static std::vector<hwc_frect_t> mCompleteFrectScalars;
-
- Area mDisplayArea;
-
- std::vector<hwc_rect_t> mDisplayFrames;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestPlaneAlpha : public Hwc2TestProperty<float> {
-public:
- explicit Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage);
-
- std::string dump() const override;
-
-protected:
- static const std::vector<float> mDefaultPlaneAlphas;
- static const std::vector<float> mBasicPlaneAlphas;
- static const std::vector<float> mCompletePlaneAlphas;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestSourceCrop : public Hwc2TestProperty<hwc_frect_t> {
-public:
- explicit Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0});
-
- std::string dump() const override;
-
- void updateBufferArea(const Area& bufferArea);
-
-protected:
- void update();
-
- const std::vector<hwc_frect_t>& mFrectScalars;
- const static std::vector<hwc_frect_t> mDefaultFrectScalars;
- const static std::vector<hwc_frect_t> mBasicFrectScalars;
- const static std::vector<hwc_frect_t> mCompleteFrectScalars;
-
- Area mBufferArea;
-
- std::vector<hwc_frect_t> mSourceCrops;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestSurfaceDamage : public Hwc2TestProperty<hwc_region_t> {
-public:
- explicit Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage);
- ~Hwc2TestSurfaceDamage();
-
- std::string dump() const override;
-
- void updateBufferArea(const Area& bufferArea);
-
-protected:
- void update();
- void freeSurfaceDamages();
-
- const std::vector<std::vector<hwc_frect_t>> &mRegionScalars;
- const static std::vector<std::vector<hwc_frect_t>> mDefaultRegionScalars;
- const static std::vector<std::vector<hwc_frect_t>> mBasicRegionScalars;
- const static std::vector<std::vector<hwc_frect_t>> mCompleteRegionScalars;
-
- Area mBufferArea = {0, 0};
-
- std::vector<hwc_region_t> mSurfaceDamages;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestTransform : public Hwc2TestProperty<hwc_transform_t> {
-public:
- explicit Hwc2TestTransform(Hwc2TestCoverage coverage);
-
- std::string dump() const override;
-
-protected:
- static const std::vector<hwc_transform_t> mDefaultTransforms;
- static const std::vector<hwc_transform_t> mBasicTransforms;
- static const std::vector<hwc_transform_t> mCompleteTransforms;
-
- static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestVisibleRegion {
-public:
- ~Hwc2TestVisibleRegion();
-
- std::string dump() const;
-
- void set(const android::Region& visibleRegion);
- hwc_region_t get() const;
- void release();
-
-protected:
- hwc_region_t mVisibleRegion = {0, nullptr};
-};
-
-#endif /* ifndef _HWC2_TEST_PROPERTIES_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
deleted file mode 100644
index e6cceb8..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-#include <sys/stat.h>
-
-#include "Hwc2TestVirtualDisplay.h"
-
-#define DIR_NAME "images"
-
-Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay(
- Hwc2TestCoverage coverage)
- : mDisplayDimension(coverage)
-{
- mDisplayDimension.setDependent(&mOutputBuffer);
- mDisplayDimension.setDependent(&mExpectedBuffer);
-}
-
-std::string Hwc2TestVirtualDisplay::dump() const
-{
- std::stringstream dmp;
-
- dmp << "virtual display: \n";
-
- mDisplayDimension.dump();
-
- return dmp.str();
-}
-
-int Hwc2TestVirtualDisplay::getOutputBuffer(buffer_handle_t* outHandle,
- android::base::unique_fd* outAcquireFence)
-{
- int32_t acquireFence;
- int ret = mOutputBuffer.getOutputBuffer(outHandle, &acquireFence);
- outAcquireFence->reset(acquireFence);
- return ret;
-}
-
-void Hwc2TestVirtualDisplay::reset()
-{
- return mDisplayDimension.reset();
-}
-
-bool Hwc2TestVirtualDisplay::advance()
-{
- return mDisplayDimension.advance();
-}
-
-UnsignedArea Hwc2TestVirtualDisplay::getDisplayDimension() const
-{
- return mDisplayDimension.get();
-}
-
-int Hwc2TestVirtualDisplay::verifyOutputBuffer(const Hwc2TestLayers* testLayers,
- const std::vector<hwc2_layer_t>* allLayers,
- const std::set<hwc2_layer_t>* clearLayers)
-{
- int ret = mExpectedBuffer.generateExpectedBuffer(testLayers, allLayers,
- clearLayers);
- if (ret)
- return ret;
-
- ComparatorResult::get().CompareBuffers(mOutputBuffer.graphicBuffer(),
- mExpectedBuffer.graphicBuffer());
-
- return 0;
-}
-
-int Hwc2TestVirtualDisplay::writeBuffersToFile(std::string name)
-{
- std::ostringstream expectedPath;
- std::ostringstream resultPath;
- int ret = mkdir(DIR_NAME, DEFFILEMODE);
- if (ret && errno != EEXIST)
- return ret;
-
- expectedPath << DIR_NAME << "/expected-" << name << ".png";
- resultPath << DIR_NAME << "/result-" << name << ".png";
-
- if (!mExpectedBuffer.writeBufferToFile(expectedPath.str()) ||
- !mOutputBuffer.writeBufferToFile(resultPath.str()))
- return -1;
-
- return 0;
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
deleted file mode 100644
index 5a74a6c..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H
-#define _HWC2_TEST_VIRTUAL_DISPLAY_H
-
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestPixelComparator.h"
-#include "Hwc2TestProperties.h"
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-class Hwc2TestVirtualDisplay {
-public:
- explicit Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage);
-
- std::string dump() const;
-
- int getOutputBuffer(buffer_handle_t* outHandle,
- android::base::unique_fd* outAcquireFence);
-
- int verifyOutputBuffer(const Hwc2TestLayers* testLayers,
- const std::vector<hwc2_layer_t>* allLayers,
- const std::set<hwc2_layer_t>* clearLayers);
-
- int writeBuffersToFile(std::string name);
- void reset();
- bool advance();
-
- UnsignedArea getDisplayDimension() const;
-
-private:
- Hwc2TestOutputBuffer mOutputBuffer;
- Hwc2TestExpectedBuffer mExpectedBuffer;
- Hwc2TestDisplayDimension mDisplayDimension;
-};
-
-#endif /* ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H */
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f842d61..3c4a791 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -36,26 +36,38 @@
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
"CachingTest.cpp",
- "CompositionTest.cpp",
+ "CompositionTest.cpp",
"DispSyncSourceTest.cpp",
"DisplayIdentificationTest.cpp",
"DisplayTransactionTest.cpp",
"EventControlThreadTest.cpp",
"EventThreadTest.cpp",
- "IdleTimerTest.cpp",
+ "HWComposerTest.cpp",
+ "OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
+ "LayerHistoryTestV2.cpp",
"LayerMetadataTest.cpp",
+ "PhaseOffsetsTest.cpp",
+ "PromiseTest.cpp",
"SchedulerTest.cpp",
"SchedulerUtilsTest.cpp",
+ "SetFrameRateTest.cpp",
"RefreshRateConfigsTest.cpp",
+ "RefreshRateSelectionTest.cpp",
"RefreshRateStatsTest.cpp",
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
+ "FrameTracerTest.cpp",
+ "TransactionApplicationTest.cpp",
+ "StrongTypingTest.cpp",
+ "VSyncDispatchTimerQueueTest.cpp",
+ "VSyncDispatchRealtimeTest.cpp",
+ "VSyncModulatorTest.cpp",
+ "VSyncPredictorTest.cpp",
+ "VSyncReactorTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
- "mock/gui/MockGraphicBufferConsumer.cpp",
- "mock/gui/MockGraphicBufferProducer.cpp",
"mock/MockDispSync.cpp",
"mock/MockEventControlThread.cpp",
"mock/MockEventThread.cpp",
@@ -63,13 +75,24 @@
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
"mock/MockTimeStats.cpp",
+ "mock/MockFrameTracer.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
"libgmock",
"libcompositionengine",
"libcompositionengine_mocks",
+ "libgui_mocks",
+ "libperfetto_client_experimental",
"librenderengine_mocks",
+ "perfetto_trace_protos",
+ ],
+ shared_libs: [
+ "libprotoutil",
+ "libstatssocket",
+ "libsurfaceflinger",
+ "libtimestats",
+ "libtimestats_proto",
],
header_libs: [
"libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 74ce540..1b8c76d 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "CachingTest"
@@ -91,3 +95,6 @@
}
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 349dd3f..32d722e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "CompositionTest"
@@ -31,21 +35,29 @@
#include <utils/String8.h>
#include "BufferQueueLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
#include "Layer.h"
-
-#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
+#include "mock/MockTimeStats.h"
#include "mock/system/window/MockNativeWindow.h"
namespace android {
namespace {
+namespace hal = android::hardware::graphics::composer::hal;
+
+using hal::Error;
+using hal::IComposer;
+using hal::IComposerClient;
+using hal::PowerMode;
+using hal::Transform;
+
using testing::_;
using testing::AtLeast;
using testing::Between;
@@ -61,16 +73,11 @@
using testing::ReturnRef;
using testing::SetArgPointee;
-using android::Hwc2::Error;
-using android::Hwc2::IComposer;
-using android::Hwc2::IComposerClient;
-using android::Hwc2::Transform;
-
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
-constexpr hwc2_display_t HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
-constexpr hwc2_layer_t HWC_LAYER = 5000;
+constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr hal::HWLayerId HWC_LAYER = 5000;
constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
@@ -95,16 +102,13 @@
mFlinger.mutableEventQueue().reset(mMessageQueue);
setupScheduler();
- EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
- EXPECT_CALL(*mPrimaryDispSync, getPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
- EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+ mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
setupComposer(0);
}
@@ -116,8 +120,6 @@
void setupComposer(int virtualDisplayCount) {
mComposer = new Hwc2::mock::Composer();
- EXPECT_CALL(*mComposer, getCapabilities())
- .WillOnce(Return(std::vector<IComposer::Capability>()));
EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
@@ -125,25 +127,31 @@
}
void setupScheduler() {
- std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
- mFlinger.mutableRefreshRateConfigs() =
- std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false,
- configs,
- /*currentConfig=*/0);
- mFlinger.mutableRefreshRateStats() =
- std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(),
- *mFlinger.mutableTimeStats(),
- /*currentConfig=*/0,
- /*powerMode=*/HWC_POWER_MODE_OFF);
- mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs());
- mScheduler->mutableEventControlThread().reset(mEventControlThread);
- mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
- EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
- sp<Scheduler::ConnectionHandle> connectionHandle =
- mScheduler->addConnection(std::move(mEventThread));
- mFlinger.mutableSfConnectionHandle() = std::move(connectionHandle);
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
- mFlinger.mutableScheduler().reset(mScheduler);
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(
+ new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(
+ new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+ EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*primaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
+
+ mFlinger.setupScheduler(std::move(primaryDispSync),
+ std::make_unique<mock::EventControlThread>(),
+ std::move(eventThread), std::move(sfEventThread));
}
void setupForceGeometryDirty() {
@@ -165,9 +173,9 @@
template <typename Case>
void captureScreenComposition();
- std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
+ std::unordered_set<hal::Capability> mDefaultCapabilities = {hal::Capability::SIDEBAND_STREAM};
- TestableScheduler* mScheduler;
+ bool mDisplayOff = false;
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
@@ -178,13 +186,11 @@
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
- std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
- mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
-
Hwc2::mock::Composer* mComposer = nullptr;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+ mock::TimeStats* mTimeStats = new mock::TimeStats();
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+ Hwc2::mock::PowerAdvisor mPowerAdvisor;
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -225,6 +231,7 @@
const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
constexpr bool useIdentityTransform = true;
constexpr bool forSystem = true;
+ constexpr bool regionSampling = false;
DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
@@ -243,7 +250,7 @@
int fd = -1;
status_t result =
mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
- useIdentityTransform, forSystem, &fd);
+ useIdentityTransform, forSystem, &fd, regionSampling);
if (fd >= 0) {
close(fd);
}
@@ -260,17 +267,13 @@
template <typename Derived>
struct BaseDisplayVariant {
static constexpr bool IS_SECURE = true;
- static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+ static constexpr hal::PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
static void setupPreconditions(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer,
- setPowerMode(HWC_DISPLAY,
- static_cast<Hwc2::IComposerClient::PowerMode>(
- Derived::INIT_POWER_MODE)))
+ EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY, Derived::INIT_POWER_MODE))
.WillOnce(Return(Error::NONE));
- FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
- true /* isPrimary */)
+ FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, true /* isPrimary */)
.setCapabilities(&test->mDefaultCapabilities)
.setPowerMode(Derived::INIT_POWER_MODE)
.inject(&test->mFlinger, test->mComposer);
@@ -283,8 +286,28 @@
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
- test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
- false /* isVirtual */, true /* isPrimary */)
+
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ auto ceDisplayArgs =
+ compositionengine::DisplayCreationArgsBuilder()
+ .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+ .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+ .setIsSecure(Derived::IS_SECURE)
+ .setLayerStackId(DEFAULT_LAYER_STACK)
+ .setPowerAdvisor(&test->mPowerAdvisor)
+ .setName(std::string("Injected display for ") +
+ test_info->test_case_name() + "." + test_info->name())
+ .build();
+
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs);
+
+ test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
+ DisplayConnectionType::Internal, HWC_DISPLAY,
+ true /* isPrimary */)
.setDisplaySurface(test->mDisplaySurface)
.setNativeWindow(test->mNativeWindow)
.setSecure(Derived::IS_SECURE)
@@ -306,18 +329,12 @@
EXPECT_CALL(*test->mComposer,
setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
.Times(1);
- EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
- // TODO: remove once we verify that we can just grab the fence from the
- // FramebufferSurface.
- EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
- return base::unique_fd();
- }));
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
@@ -329,17 +346,17 @@
template <typename Case>
static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillRepeatedly(
- [](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
- EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
- EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- displaySettings.physicalDisplay);
- EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- displaySettings.clip);
- return NO_ERROR;
- });
+ .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
+ EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.clip);
+ return NO_ERROR;
+ });
}
static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
@@ -351,14 +368,24 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+
EXPECT_CALL(*test->mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
.Times(1);
}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+ }
+
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, validateDisplay(HWC_DISPLAY, _, _)).Times(1);
+ }
+
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mDisplaySurface,
- prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
+ prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GPU))
.Times(1);
EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
.WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
@@ -368,18 +395,18 @@
.WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
Return(0)));
EXPECT_CALL(*test->mRenderEngine, drawLayers)
- .WillRepeatedly(
- [](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
- const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
- EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
- EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- displaySettings.physicalDisplay);
- EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
- displaySettings.clip);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
- return NO_ERROR;
- });
+ .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
+ const std::vector<const renderengine::LayerSettings*>&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
+ base::unique_fd*) -> status_t {
+ EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.physicalDisplay);
+ EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ displaySettings.clip);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
+ return NO_ERROR;
+ });
}
template <typename Case>
@@ -410,7 +437,7 @@
};
struct PoweredOffDisplaySetupVariant : public BaseDisplayVariant<PoweredOffDisplaySetupVariant> {
- static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
+ static constexpr hal::PowerMode INIT_POWER_MODE = hal::PowerMode::OFF;
template <typename Case>
static void setupPreconditionCallExpectations(CompositionTest*) {}
@@ -429,6 +456,8 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest*) {}
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
@@ -513,11 +542,11 @@
EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
enqueueBuffer(test, layer);
- Mock::VerifyAndClear(test->mMessageQueue);
+ Mock::VerifyAndClearExpectations(test->mMessageQueue);
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
bool ignoredRecomputeVisibleRegions;
- layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
Mock::VerifyAndClear(test->mRenderEngine);
}
@@ -532,69 +561,85 @@
}
static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
- // TODO: Coverage of other values
- EXPECT_CALL(*test->mComposer,
- setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
- .Times(1);
- // TODO: Coverage of other values for origin
- EXPECT_CALL(*test->mComposer,
- setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
- IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
- LayerProperties::HEIGHT})))
- .Times(1);
- EXPECT_CALL(*test->mComposer,
- setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
- .Times(1);
- // TODO: Coverage of other values
- EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
- // TODO: Coverage of other values
- EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
+ if (!test->mDisplayOff) {
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer,
+ setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
+ .Times(1);
+ // TODO: Coverage of other values for origin
+ EXPECT_CALL(*test->mComposer,
+ setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})))
+ .Times(1);
+ EXPECT_CALL(*test->mComposer,
+ setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
+ .Times(1);
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
+ // TODO: Coverage of other values
+ EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
- // These expectations retire on saturation as the code path these
- // expectations are for appears to make an extra call to them.
- // TODO: Investigate this extra call
- EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
- .Times(AtLeast(1))
- .RetiresOnSaturation();
+ // These expectations retire on saturation as the code path these
+ // expectations are for appears to make an extra call to them.
+ // TODO: Investigate this extra call
+ EXPECT_CALL(*test->mComposer,
+ setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
+ .Times(AtLeast(1))
+ .RetiresOnSaturation();
+ }
}
static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer,
- setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
- IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
- LayerProperties::HEIGHT})))
- .Times(1);
+ if (!test->mDisplayOff) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})))
+ .Times(1);
+ }
}
static void setupHwcSetSourceCropColorCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer,
- setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
- IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
- .Times(1);
+ if (!test->mDisplayOff) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
+ .Times(1);
+ }
}
static void setupHwcSetPerFrameCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer,
- setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
- std::vector<IComposerClient::Rect>({IComposerClient::Rect(
- {0, 0, LayerProperties::WIDTH,
- LayerProperties::HEIGHT})})))
- .Times(1);
+ if (!test->mDisplayOff) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
+ std::vector<IComposerClient::Rect>(
+ {IComposerClient::Rect(
+ {0, 0, LayerProperties::WIDTH,
+ LayerProperties::HEIGHT})})))
+ .Times(1);
+ }
}
static void setupHwcSetPerFrameColorCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+ if (!test->mDisplayOff) {
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _))
+ .Times(1);
- // TODO: use COLOR
- EXPECT_CALL(*test->mComposer,
- setLayerColor(HWC_DISPLAY, HWC_LAYER,
- IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
- .Times(1);
+ // TODO: use COLOR
+ EXPECT_CALL(*test->mComposer,
+ setLayerColor(HWC_DISPLAY, HWC_LAYER,
+ IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
+ .Times(1);
+ }
}
static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
- EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+ if (!test->mDisplayOff) {
+ EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _))
+ .Times(1);
+ EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+ }
setupBufferLayerPostFrameCallExpectations(test);
}
@@ -602,7 +647,7 @@
static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -612,16 +657,22 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so gtet the back layer.
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
- EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
- EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
- EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
- EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
- EXPECT_EQ(false, layer.source.buffer.isOpaque);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ if (layerSettings.empty()) {
+ ADD_FAILURE() << "layerSettings was not expected to be empty in "
+ "setupREBufferCompositionCommonCallExpectations "
+ "verification lambda";
+ return NO_ERROR;
+ }
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
+ EXPECT_THAT(layer->source.buffer.fence, Not(IsNull()));
+ EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName);
+ EXPECT_EQ(false, layer->source.buffer.isY410BT2020);
+ EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha);
+ EXPECT_EQ(false, layer->source.buffer.isOpaque);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
return NO_ERROR;
});
}
@@ -645,7 +696,7 @@
static void setupREColorCompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -655,14 +706,20 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+ if (layerSettings.empty()) {
+ ADD_FAILURE()
+ << "layerSettings was not expected to be empty in "
+ "setupREColorCompositionCallExpectations verification lambda";
+ return NO_ERROR;
+ }
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, IsNull());
EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2]),
- layer.source.solidColor);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+ layer->source.solidColor);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
return NO_ERROR;
});
}
@@ -674,7 +731,9 @@
struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
-struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {};
+struct EffectLayerProperties : public BaseLayerProperties<EffectLayerProperties> {
+ static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
+};
struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerProperties> {
using Base = BaseLayerProperties<SidebandLayerProperties>;
@@ -715,7 +774,7 @@
static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& layerSettings,
+ const std::vector<const renderengine::LayerSettings*>& layerSettings,
ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -725,12 +784,18 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
- renderengine::LayerSettings layer = layerSettings.back();
- EXPECT_THAT(layer.source.buffer.buffer, IsNull());
- EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
- EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
- EXPECT_EQ(1.0f, layer.alpha);
+ if (layerSettings.empty()) {
+ ADD_FAILURE() << "layerSettings was not expected to be empty in "
+ "setupInsecureREBufferCompositionCommonCallExpectations "
+ "verification lambda";
+ return NO_ERROR;
+ }
+ const renderengine::LayerSettings* layer = layerSettings.back();
+ EXPECT_THAT(layer->source.buffer.buffer, IsNull());
+ EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor);
+ EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+ EXPECT_EQ(1.0f, layer->alpha);
return NO_ERROR;
});
}
@@ -769,13 +834,16 @@
struct BaseLayerVariant {
template <typename L, typename F>
static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
- EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(0);
sp<L> layer = factory();
+ // Layer should be registered with scheduler.
+ EXPECT_EQ(1, test->mFlinger.scheduler()->layerHistorySize());
+
Mock::VerifyAndClear(test->mComposer);
Mock::VerifyAndClear(test->mRenderEngine);
- Mock::VerifyAndClear(test->mMessageQueue);
+ Mock::VerifyAndClearExpectations(test->mMessageQueue);
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
@@ -783,8 +851,7 @@
layerDrawingState.active.h = 100;
layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
- layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform());
- layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
+ layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform(), 0.f /* shadowRadius */);
return layer;
}
@@ -793,19 +860,13 @@
EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
- std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
- outputLayers.emplace_back(test->mDisplay->getCompositionDisplay()
- ->getOrCreateOutputLayer(DEFAULT_DISPLAY_ID,
- layer->getCompositionLayer(),
- layer));
-
- test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
+ auto outputLayer = test->mDisplay->getCompositionDisplay()->injectOutputLayerForTest(
+ layer->getCompositionEngineLayerFE());
+ outputLayer->editState().visibleRegion = Region(Rect(0, 0, 100, 100));
+ outputLayer->editState().outputSpaceVisibleRegion = Region(Rect(0, 0, 100, 100));
Mock::VerifyAndClear(test->mComposer);
- Vector<sp<Layer>> layers;
- layers.add(layer);
- test->mDisplay->setVisibleLayersSortedByZ(layers);
test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
}
@@ -813,23 +874,26 @@
EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
.WillOnce(Return(Error::NONE));
- test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(
- std::vector<std::unique_ptr<compositionengine::OutputLayer>>());
+ test->mDisplay->getCompositionDisplay()->clearOutputLayers();
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
+
+ // Layer should be unregistered with scheduler.
+ test->mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+ EXPECT_EQ(0, test->mFlinger.scheduler()->layerHistorySize());
}
};
template <typename LayerProperties>
-struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> {
using Base = BaseLayerVariant<LayerProperties>;
- using FlingerLayerType = sp<ColorLayer>;
+ using FlingerLayerType = sp<EffectLayer>;
static FlingerLayerType createLayer(CompositionTest* test) {
- FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
- return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
- String8("test-layer"), LayerProperties::WIDTH,
- LayerProperties::HEIGHT,
- LayerProperties::LAYER_FLAGS, LayerMetadata()));
+ FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
+ return new EffectLayer(
+ LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(), "test-layer",
+ LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS, LayerMetadata()));
});
auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
@@ -866,11 +930,12 @@
FlingerLayerType layer =
Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
- return new BufferQueueLayer(
- LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
- String8("test-layer"), LayerProperties::WIDTH,
- LayerProperties::HEIGHT,
- LayerProperties::LAYER_FLAGS, LayerMetadata()));
+ sp<Client> client;
+ LayerCreationArgs args(test->mFlinger.mFlinger.get(), client, "test-layer",
+ LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS, LayerMetadata());
+ args.textureName = test->mFlinger.mutableTexturePool().back();
+ return new BufferQueueLayer(args);
});
LayerProperties::setupLayerState(test, layer);
@@ -879,7 +944,7 @@
}
static void cleanupInjectedLayers(CompositionTest* test) {
- EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(1);
+ EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1);
Base::cleanupInjectedLayers(test);
}
@@ -924,12 +989,14 @@
template <IComposerClient::Composition CompositionType>
struct KeepCompositionTypeVariant {
- static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(CompositionType);
+ static constexpr hal::Composition TYPE = CompositionType;
static void setupHwcSetCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer,
- setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
- .Times(1);
+ if (!test->mDisplayOff) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
+ .Times(1);
+ }
}
static void setupHwcGetCallExpectations(CompositionTest* test) {
@@ -940,12 +1007,14 @@
template <IComposerClient::Composition InitialCompositionType,
IComposerClient::Composition FinalCompositionType>
struct ChangeCompositionTypeVariant {
- static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(FinalCompositionType);
+ static constexpr hal::Composition TYPE = FinalCompositionType;
static void setupHwcSetCallExpectations(CompositionTest* test) {
- EXPECT_CALL(*test->mComposer,
- setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
- .Times(1);
+ if (!test->mDisplayOff) {
+ EXPECT_CALL(*test->mComposer,
+ setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
+ .Times(1);
+ }
}
static void setupHwcGetCallExpectations(CompositionTest* test) {
@@ -996,14 +1065,46 @@
template <typename Case>
static void setupCallExpectations(CompositionTest* test) {
Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcClientCompositionCallExpectations(test);
Case::Display::setupRECompositionCallExpectations(test);
Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
}
};
-struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+struct ForcedClientCompositionResultVariant : public CompositionResultBaseVariant {
static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
- layer->forceClientComposition(test->mDisplay);
+ const auto outputLayer =
+ TestableSurfaceFlinger::findOutputLayerForDisplay(layer, test->mDisplay);
+ LOG_FATAL_IF(!outputLayer);
+ outputLayer->editState().forceClientComposition = true;
+ }
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+ Case::Display::setupRECompositionCallExpectations(test);
+ Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+ }
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+ template <typename Case>
+ static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+struct ForcedClientCompositionViaDebugOptionResultVariant : public CompositionResultBaseVariant {
+ static void setupLayerState(CompositionTest* test, sp<Layer>) {
+ test->mFlinger.mutableDebugDisableHWC() = true;
+ }
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+ Case::Display::setupRECompositionCallExpectations(test);
+ Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
}
template <typename Case>
@@ -1080,11 +1181,11 @@
static void cleanup(CompositionTest* test) {
Layer::cleanupInjectedLayers(test);
- for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
- hwcDisplay->mutableLayers().clear();
+ for (auto& displayData : test->mFlinger.mutableHwcDisplayData()) {
+ static_cast<TestableSurfaceFlinger::HWC2Display*>(displayData.second.hwcDisplay.get())
+ ->mutableLayers()
+ .clear();
}
-
- test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
}
};
@@ -1146,31 +1247,31 @@
* Single-color layers
*/
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) {
displayRefreshCompositionDirtyGeometry<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
HwcCompositionResultVariant>>();
}
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) {
displayRefreshCompositionDirtyFrame<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
HwcCompositionResultVariant>>();
}
-TEST_F(CompositionTest, REComposedColorLayer) {
+TEST_F(CompositionTest, REComposedEffectLayer) {
displayRefreshCompositionDirtyFrame<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
IComposerClient::Composition::CLIENT>,
RECompositionResultVariant>>();
}
-TEST_F(CompositionTest, captureScreenColorLayer) {
+TEST_F(CompositionTest, captureScreenEffectLayer) {
captureScreenComposition<
- CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+ CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
NoCompositionTypeVariant, REScreenshotResultVariant>>();
}
@@ -1299,6 +1400,7 @@
*/
TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyGeometry) {
+ mDisplayOff = true;
displayRefreshCompositionDirtyGeometry<CompositionCase<
PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
@@ -1306,6 +1408,7 @@
}
TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyFrame) {
+ mDisplayOff = true;
displayRefreshCompositionDirtyFrame<CompositionCase<
PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
@@ -1313,6 +1416,7 @@
}
TEST_F(CompositionTest, displayOffREComposedNormalBufferLayer) {
+ mDisplayOff = true;
displayRefreshCompositionDirtyFrame<CompositionCase<
PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
@@ -1326,5 +1430,26 @@
NoCompositionTypeVariant, REScreenshotResultVariant>>();
}
+/* ------------------------------------------------------------------------
+ * Client composition forced through debug/developer settings
+ */
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyGeometry) {
+ displayRefreshCompositionDirtyGeometry<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+ ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyFrame) {
+ displayRefreshCompositionDirtyFrame<
+ CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+ KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+ ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 0aa8cf5..afebc40 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -43,7 +43,7 @@
void createDispSync();
void createDispSyncSource();
- void onVSyncEvent(nsecs_t when) override;
+ void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
std::unique_ptr<mock::DispSync> mDispSync;
std::unique_ptr<DispSyncSource> mDispSyncSource;
@@ -51,7 +51,6 @@
AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
- static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms;
static constexpr int mIterations = 100;
};
@@ -67,7 +66,7 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when) {
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) {
ALOGD("onVSyncEvent: %" PRId64, when);
mVSyncEventCallRecorder.recordCall(when);
@@ -79,8 +78,7 @@
void DispSyncSourceTest::createDispSyncSource() {
createDispSync();
- mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(),
- mOffsetThresholdForNextVsync.count(), true,
+ mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
"DispSyncSourceTest");
mDispSyncSource->setCallback(this);
}
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 55995d0..2a0e913 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <functional>
+#include <string_view>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -61,11 +64,73 @@
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
+const unsigned char kPanasonicTvEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x34\xa9\x96\xa2\x01\x01\x01"
+ "\x01\x00\x1d\x01\x03\x80\x80\x48\x78\x0a\xda\xff\xa3\x58\x4a"
+ "\xa2\x29\x17\x49\x4b\x20\x08\x00\x31\x40\x61\x40\x01\x01\x01"
+ "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x08\xe8\x00\x30\xf2\x70"
+ "\x5a\x80\xb0\x58\x8a\x00\xba\x88\x21\x00\x00\x1e\x02\x3a\x80"
+ "\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\xba\x88\x21\x00\x00\x1e"
+ "\x00\x00\x00\xfc\x00\x50\x61\x6e\x61\x73\x6f\x6e\x69\x63\x2d"
+ "\x54\x56\x0a\x00\x00\x00\xfd\x00\x17\x3d\x0f\x88\x3c\x00\x0a"
+ "\x20\x20\x20\x20\x20\x20\x01\x1d\x02\x03\x6b\xf0\x57\x61\x60"
+ "\x10\x1f\x66\x65\x05\x14\x20\x21\x22\x04\x13\x03\x12\x07\x16"
+ "\x5d\x5e\x5f\x62\x63\x64\x2c\x0d\x07\x01\x15\x07\x50\x57\x07"
+ "\x01\x67\x04\x03\x83\x0f\x00\x00\x6e\x03\x0c\x00\x20\x00\x38"
+ "\x3c\x2f\x08\x80\x01\x02\x03\x04\x67\xd8\x5d\xc4\x01\x78\x80"
+ "\x03\xe2\x00\x4b\xe3\x05\xff\x01\xe2\x0f\x33\xe3\x06\x0f\x01"
+ "\xe5\x01\x8b\x84\x90\x01\xeb\x01\x46\xd0\x00\x44\x03\x70\x80"
+ "\x5e\x75\x94\xe6\x11\x46\xd0\x00\x70\x00\x66\x21\x56\xaa\x51"
+ "\x00\x1e\x30\x46\x8f\x33\x00\xba\x88\x21\x00\x00\x1e\x00\x00"
+ "\xc8";
+
+const unsigned char kHisenseTvEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x20\xa3\x00\x00\x00\x00\x00"
+ "\x00\x12\x1d\x01\x03\x80\x00\x00\x78\x0a\xd7\xa5\xa2\x59\x4a"
+ "\x96\x24\x14\x50\x54\xa3\x08\x00\xd1\xc0\xb3\x00\x81\x00\x81"
+ "\x80\x81\x40\x81\xc0\x01\x01\x01\x01\x02\x3a\x80\x18\x71\x38"
+ "\x2d\x40\x58\x2c\x45\x00\x3f\x43\x21\x00\x00\x1a\x02\x3a\x80"
+ "\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\x3f\x43\x21\x00\x00\x1a"
+ "\x00\x00\x00\xfd\x00\x1e\x4c\x1e\x5a\x1e\x00\x0a\x20\x20\x20"
+ "\x20\x20\x20\x00\x00\x00\xfc\x00\x48\x69\x73\x65\x6e\x73\x65"
+ "\x0a\x20\x20\x20\x20\x20\x01\x47\x02\x03\x2d\x71\x50\x90\x05"
+ "\x04\x03\x07\x02\x06\x01\x1f\x14\x13\x12\x16\x11\x15\x20\x2c"
+ "\x09\x07\x03\x15\x07\x50\x57\x07\x00\x39\x07\xbb\x66\x03\x0c"
+ "\x00\x12\x34\x00\x83\x01\x00\x00\x01\x1d\x00\x72\x51\xd0\x1e"
+ "\x20\x6e\x28\x55\x00\xc4\x8e\x21\x00\x00\x1e\x01\x1d\x80\x18"
+ "\x71\x1c\x16\x20\x58\x2c\x25\x00\xc4\x8e\x21\x00\x00\x9e\x8c"
+ "\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x13\x8e\x21\x00"
+ "\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ "\x07";
+
+const unsigned char kCtlDisplayEdid[] =
+ "\x00\xff\xff\xff\xff\xff\xff\x00\x0e\x8c\x9d\x24\x00\x00\x00\x00"
+ "\xff\x17\x01\x04\xa5\x34\x1d\x78\x3a\xa7\x25\xa4\x57\x51\xa0\x26"
+ "\x10\x50\x54\xbf\xef\x80\xb3\x00\xa9\x40\x95\x00\x81\x40\x81\x80"
+ "\x95\x0f\x71\x4f\x90\x40\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c"
+ "\x45\x00\x09\x25\x21\x00\x00\x1e\x66\x21\x50\xb0\x51\x00\x1b\x30"
+ "\x40\x70\x36\x00\x09\x25\x21\x00\x00\x1e\x00\x00\x00\xfd\x00\x31"
+ "\x4c\x1e\x52\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc"
+ "\x00\x4c\x50\x32\x33\x36\x31\x0a\x20\x20\x20\x20\x20\x20\x01\x3e"
+ "\x02\x03\x22\xf2\x4f\x90\x9f\x05\x14\x04\x13\x03\x02\x12\x11\x07"
+ "\x06\x16\x15\x01\x23\x09\x07\x07\x83\x01\x00\x00\x65\xb9\x14\x00"
+ "\x04\x00\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\x09\x25"
+ "\x21\x00\x00\x1e\x02\x3a\x80\xd0\x72\x38\x2d\x40\x10\x2c\x45\x80"
+ "\x09\x25\x21\x00\x00\x1e\x01\x1d\x00\x72\x51\xd0\x1e\x20\x6e\x28"
+ "\x55\x00\x09\x25\x21\x00\x00\x1e\x8c\x0a\xd0\x8a\x20\xe0\x2d\x10"
+ "\x10\x3e\x96\x00\x09\x25\x21\x00\x00\x18\x00\x00\x00\x00\x00\x00"
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4";
+
template <size_t N>
DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) {
return DisplayIdentificationData(bytes, bytes + N - 1);
}
+uint32_t hash(const char* str) {
+ return static_cast<uint32_t>(std::hash<std::string_view>()(str));
+}
+
} // namespace
const DisplayIdentificationData& getInternalEdid() {
@@ -83,12 +148,30 @@
return data;
}
+const DisplayIdentificationData& getPanasonicTvEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kPanasonicTvEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getHisenseTvEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kHisenseTvEdid);
+ return data;
+}
+
+const DisplayIdentificationData& getCtlDisplayEdid() {
+ static const DisplayIdentificationData data = asDisplayIdentificationData(kCtlDisplayEdid);
+ return data;
+}
+
TEST(DisplayIdentificationTest, isEdid) {
EXPECT_FALSE(isEdid({}));
EXPECT_TRUE(isEdid(getInternalEdid()));
EXPECT_TRUE(isEdid(getExternalEdid()));
EXPECT_TRUE(isEdid(getExternalEedid()));
+ EXPECT_TRUE(isEdid(getPanasonicTvEdid()));
+ EXPECT_TRUE(isEdid(getHisenseTvEdid()));
+ EXPECT_TRUE(isEdid(getCtlDisplayEdid()));
}
TEST(DisplayIdentificationTest, parseEdid) {
@@ -97,19 +180,86 @@
EXPECT_EQ(0x4ca3u, edid->manufacturerId);
EXPECT_STREQ("SEC", edid->pnpId.data());
// ASCII text should be used as fallback if display name and serial number are missing.
- EXPECT_EQ("121AT11-801", edid->displayName);
+ EXPECT_EQ(hash("121AT11-801"), edid->modelHash);
+ EXPECT_TRUE(edid->displayName.empty());
+ EXPECT_EQ(12610, edid->productId);
+ EXPECT_EQ(21, edid->manufactureOrModelYear);
+ EXPECT_EQ(0, edid->manufactureWeek);
+ EXPECT_FALSE(edid->cea861Block);
edid = parseEdid(getExternalEdid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x22f0u, edid->manufacturerId);
EXPECT_STREQ("HWP", edid->pnpId.data());
+ EXPECT_EQ(hash("HP ZR30w"), edid->modelHash);
EXPECT_EQ("HP ZR30w", edid->displayName);
+ EXPECT_EQ(10348, edid->productId);
+ EXPECT_EQ(22, edid->manufactureOrModelYear);
+ EXPECT_EQ(2, edid->manufactureWeek);
+ EXPECT_FALSE(edid->cea861Block);
edid = parseEdid(getExternalEedid());
ASSERT_TRUE(edid);
EXPECT_EQ(0x4c2du, edid->manufacturerId);
EXPECT_STREQ("SAM", edid->pnpId.data());
+ EXPECT_EQ(hash("SAMSUNG"), edid->modelHash);
EXPECT_EQ("SAMSUNG", edid->displayName);
+ EXPECT_EQ(2302, edid->productId);
+ EXPECT_EQ(21, edid->manufactureOrModelYear);
+ EXPECT_EQ(41, edid->manufactureWeek);
+ ASSERT_TRUE(edid->cea861Block);
+ ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+ auto physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+ EXPECT_EQ(2, physicalAddress.a);
+ EXPECT_EQ(0, physicalAddress.b);
+ EXPECT_EQ(0, physicalAddress.c);
+ EXPECT_EQ(0, physicalAddress.d);
+
+ edid = parseEdid(getPanasonicTvEdid());
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(13481, edid->manufacturerId);
+ EXPECT_STREQ("MEI", edid->pnpId.data());
+ EXPECT_EQ(hash("Panasonic-TV"), edid->modelHash);
+ EXPECT_EQ("Panasonic-TV", edid->displayName);
+ EXPECT_EQ(41622, edid->productId);
+ EXPECT_EQ(29, edid->manufactureOrModelYear);
+ EXPECT_EQ(0, edid->manufactureWeek);
+ ASSERT_TRUE(edid->cea861Block);
+ ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+ physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+ EXPECT_EQ(2, physicalAddress.a);
+ EXPECT_EQ(0, physicalAddress.b);
+ EXPECT_EQ(0, physicalAddress.c);
+ EXPECT_EQ(0, physicalAddress.d);
+
+ edid = parseEdid(getHisenseTvEdid());
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(8355, edid->manufacturerId);
+ EXPECT_STREQ("HEC", edid->pnpId.data());
+ EXPECT_EQ(hash("Hisense"), edid->modelHash);
+ EXPECT_EQ("Hisense", edid->displayName);
+ EXPECT_EQ(0, edid->productId);
+ EXPECT_EQ(29, edid->manufactureOrModelYear);
+ EXPECT_EQ(18, edid->manufactureWeek);
+ ASSERT_TRUE(edid->cea861Block);
+ ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+ physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+ EXPECT_EQ(1, physicalAddress.a);
+ EXPECT_EQ(2, physicalAddress.b);
+ EXPECT_EQ(3, physicalAddress.c);
+ EXPECT_EQ(4, physicalAddress.d);
+
+ edid = parseEdid(getCtlDisplayEdid());
+ ASSERT_TRUE(edid);
+ EXPECT_EQ(3724, edid->manufacturerId);
+ EXPECT_STREQ("CTL", edid->pnpId.data());
+ EXPECT_EQ(hash("LP2361"), edid->modelHash);
+ EXPECT_EQ("LP2361", edid->displayName);
+ EXPECT_EQ(9373, edid->productId);
+ EXPECT_EQ(23, edid->manufactureOrModelYear);
+ EXPECT_EQ(0xff, edid->manufactureWeek);
+ ASSERT_TRUE(edid->cea861Block);
+ EXPECT_FALSE(edid->cea861Block->hdmiVendorDataBlock);
}
TEST(DisplayIdentificationTest, parseInvalidEdid) {
@@ -122,13 +272,15 @@
auto edid = parseEdid(data);
ASSERT_TRUE(edid);
// Serial number should be used as fallback if display name is invalid.
- EXPECT_EQ("CN4202137Q", edid->displayName);
+ const auto modelHash = hash("CN4202137Q");
+ EXPECT_EQ(modelHash, edid->modelHash);
+ EXPECT_TRUE(edid->displayName.empty());
// Parsing should succeed even if EDID is truncated.
data.pop_back();
edid = parseEdid(data);
ASSERT_TRUE(edid);
- EXPECT_EQ("CN4202137Q", edid->displayName);
+ EXPECT_EQ(modelHash, edid->modelHash);
}
TEST(DisplayIdentificationTest, getPnpId) {
@@ -156,6 +308,93 @@
EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
}
+TEST(DisplayIdentificationTest, deviceProductInfo) {
+ using ManufactureYear = DeviceProductInfo::ManufactureYear;
+ using ManufactureWeekAndYear = DeviceProductInfo::ManufactureWeekAndYear;
+ using ModelYear = DeviceProductInfo::ModelYear;
+ using RelativeAddress = DeviceProductInfo::RelativeAddress;
+
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getInternalEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("", info.name.data());
+ EXPECT_STREQ("SEC", info.manufacturerPnpId.data());
+ EXPECT_STREQ("12610", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
+ EXPECT_EQ(2011, std::get<ManufactureYear>(info.manufactureOrModelDate).year);
+ EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("HP ZR30w", info.name.data());
+ EXPECT_STREQ("HWP", info.manufacturerPnpId.data());
+ EXPECT_STREQ("10348", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2012, date.year);
+ EXPECT_EQ(2, date.week);
+ EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEedid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("SAMSUNG", info.name.data());
+ EXPECT_STREQ("SAM", info.manufacturerPnpId.data());
+ EXPECT_STREQ("2302", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2011, date.year);
+ EXPECT_EQ(41, date.week);
+ EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getPanasonicTvEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("Panasonic-TV", info.name.data());
+ EXPECT_STREQ("MEI", info.manufacturerPnpId.data());
+ EXPECT_STREQ("41622", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2019, date.year);
+ EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getHisenseTvEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("Hisense", info.name.data());
+ EXPECT_STREQ("HEC", info.manufacturerPnpId.data());
+ EXPECT_STREQ("0", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+ const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+ EXPECT_EQ(2019, date.year);
+ EXPECT_EQ(18, date.week);
+ EXPECT_EQ((RelativeAddress{{1, 2, 3, 4}}), info.relativeAddress);
+ }
+ {
+ const auto displayIdInfo = parseDisplayIdentificationData(0, getCtlDisplayEdid());
+ ASSERT_TRUE(displayIdInfo);
+ ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+ const auto& info = *displayIdInfo->deviceProductInfo;
+ EXPECT_STREQ("LP2361", info.name.data());
+ EXPECT_STREQ("CTL", info.manufacturerPnpId.data());
+ EXPECT_STREQ("9373", info.productId.data());
+ ASSERT_TRUE(std::holds_alternative<ModelYear>(info.manufactureOrModelDate));
+ EXPECT_EQ(2013, std::get<ModelYear>(info.manufactureOrModelDate).year);
+ EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+ }
+}
+
TEST(DisplayIdentificationTest, getFallbackDisplayId) {
// Manufacturer ID should be invalid.
ASSERT_FALSE(getPnpId(getFallbackDisplayId(0)));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index f40996e..ce5f35c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
@@ -21,45 +25,60 @@
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/mock/Display.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/DisplaySurface.h>
+#include <compositionengine/mock/RenderSurface.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <gui/mock/GraphicBufferConsumer.h>
+#include <gui/mock/GraphicBufferProducer.h>
#include <log/log.h>
#include <renderengine/mock/RenderEngine.h>
#include <ui/DebugUtils.h>
#include "DisplayIdentificationTest.h"
-#include "Scheduler/RefreshRateConfigs.h"
#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
#include "mock/MockDispSync.h"
#include "mock/MockEventControlThread.h"
#include "mock/MockEventThread.h"
#include "mock/MockMessageQueue.h"
#include "mock/MockNativeWindowSurface.h"
#include "mock/MockSurfaceInterceptor.h"
-#include "mock/gui/MockGraphicBufferConsumer.h"
-#include "mock/gui/MockGraphicBufferProducer.h"
#include "mock/system/window/MockNativeWindow.h"
namespace android {
namespace {
+namespace hal = android::hardware::graphics::composer::hal;
+
using testing::_;
+using testing::AnyNumber;
using testing::DoAll;
using testing::Mock;
using testing::ResultOf;
using testing::Return;
+using testing::ReturnRefOfCopy;
using testing::SetArgPointee;
+using testing::StrictMock;
-using android::Hwc2::ColorMode;
-using android::Hwc2::Error;
-using android::Hwc2::Hdr;
-using android::Hwc2::IComposer;
-using android::Hwc2::IComposerClient;
-using android::Hwc2::PerFrameMetadataKey;
-using android::Hwc2::RenderIntent;
+using hal::ColorMode;
+using hal::Connection;
+using hal::DisplayCapability;
+using hal::DisplayType;
+using hal::Error;
+using hal::Hdr;
+using hal::HWDisplayId;
+using hal::IComposer;
+using hal::IComposerClient;
+using hal::PerFrameMetadataKey;
+using hal::PowerMode;
+using hal::RenderIntent;
using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
@@ -70,7 +89,7 @@
constexpr int32_t DEFAULT_DPI = 320;
constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
-constexpr int HWC_POWER_MODE_LEET = 1337; // An out of range power mode value
+constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
/* ------------------------------------------------------------------------
* Boolean avoidance
@@ -96,19 +115,19 @@
DisplayTransactionTest();
~DisplayTransactionTest() override;
- void setupScheduler();
-
// --------------------------------------------------------------------
// Mock/Fake injection
+ void injectMockScheduler();
void injectMockComposer(int virtualDisplayCount);
void injectFakeBufferQueueFactory();
void injectFakeNativeWindowSurfaceFactory();
+ sp<DisplayDevice> injectDefaultInternalDisplay(std::function<void(FakeDisplayDeviceInjector&)>);
// --------------------------------------------------------------------
// Postcondition helpers
- bool hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId);
+ bool hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId);
bool hasTransactionFlagSet(int flag);
bool hasDisplayDevice(sp<IBinder> displayToken);
sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
@@ -120,13 +139,10 @@
// --------------------------------------------------------------------
// Test instances
- TestableScheduler* mScheduler;
TestableSurfaceFlinger mFlinger;
- mock::EventThread* mEventThread = new mock::EventThread();
- mock::EventThread* mSFEventThread = new mock::EventThread();
- mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+ Hwc2::mock::PowerAdvisor mPowerAdvisor;
// These mocks are created by the test, but are destroyed by SurfaceFlinger
// by virtue of being stored into a std::unique_ptr. However we still need
@@ -135,7 +151,11 @@
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync;
+ mock::EventControlThread* mEventControlThread = new mock::EventControlThread;
+ mock::EventThread* mEventThread = new mock::EventThread;
+ mock::EventThread* mSFEventThread = new mock::EventThread;
// These mocks are created only when expected to be created via a factory.
sp<mock::GraphicBufferConsumer> mConsumer;
@@ -151,7 +171,7 @@
// Default to no wide color display support configured
mFlinger.mutableHasWideColorDisplay() = false;
mFlinger.mutableUseColorManagement() = false;
- mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
// Default to using HWC virtual displays
mFlinger.mutableUseHwcVirtualDisplays() = true;
@@ -165,7 +185,7 @@
return nullptr;
});
- setupScheduler();
+ injectMockScheduler();
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
@@ -179,35 +199,25 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
-void DisplayTransactionTest::setupScheduler() {
- std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
- mFlinger.mutableRefreshRateConfigs() =
- std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfig=*/0);
- mFlinger.mutableRefreshRateStats() =
- std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(),
- *mFlinger.mutableTimeStats(),
- /*currentConfig=*/0,
- /*powerMode=*/HWC_POWER_MODE_OFF);
- mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs());
- mScheduler->mutableEventControlThread().reset(mEventControlThread);
- mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+void DisplayTransactionTest::injectMockScheduler() {
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*mEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(mEventThread, ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
- sp<Scheduler::ConnectionHandle> sfConnectionHandle =
- mScheduler->addConnection(std::unique_ptr<EventThread>(mSFEventThread));
- mFlinger.mutableSfConnectionHandle() = std::move(sfConnectionHandle);
- sp<Scheduler::ConnectionHandle> appConnectionHandle =
- mScheduler->addConnection(std::unique_ptr<EventThread>(mEventThread));
- mFlinger.mutableAppConnectionHandle() = std::move(appConnectionHandle);
- mFlinger.mutableScheduler().reset(mScheduler);
+ EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*mSFEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(mSFEventThread, ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ mFlinger.setupScheduler(std::unique_ptr<DispSync>(mPrimaryDispSync),
+ std::unique_ptr<EventControlThread>(mEventControlThread),
+ std::unique_ptr<EventThread>(mEventThread),
+ std::unique_ptr<EventThread>(mSFEventThread));
}
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
mComposer = new Hwc2::mock::Composer();
- EXPECT_CALL(*mComposer, getCapabilities())
- .WillOnce(Return(std::vector<IComposer::Capability>()));
EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
@@ -238,7 +248,51 @@
});
}
-bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) {
+sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay(
+ std::function<void(FakeDisplayDeviceInjector&)> injectExtra) {
+ constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
+ constexpr int DEFAULT_DISPLAY_WIDTH = 1080;
+ constexpr int DEFAULT_DISPLAY_HEIGHT = 1920;
+ constexpr HWDisplayId DEFAULT_DISPLAY_HWC_DISPLAY_ID = 0;
+
+ // The DisplayDevice is required to have a framebuffer (behind the
+ // ANativeWindow interface) which uses the actual hardware display
+ // size.
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+ EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
+ EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());
+
+ auto compositionDisplay = compositionengine::impl::
+ createDisplay(mFlinger.getCompositionEngine(),
+ compositionengine::DisplayCreationArgsBuilder()
+ .setPhysical(
+ {DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+ .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+ .setPowerAdvisor(&mPowerAdvisor)
+ .build());
+
+ auto injector =
+ FakeDisplayDeviceInjector(mFlinger, compositionDisplay, DisplayConnectionType::Internal,
+ DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */);
+
+ injector.setNativeWindow(mNativeWindow);
+ if (injectExtra) {
+ injectExtra(injector);
+ }
+
+ auto displayDevice = injector.inject();
+
+ Mock::VerifyAndClear(mNativeWindow.get());
+
+ return displayDevice;
+}
+
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) {
return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
}
@@ -296,8 +350,8 @@
static std::optional<DisplayId> get() {
if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
return getFallbackDisplayId(static_cast<bool>(PhysicalDisplay::PRIMARY)
- ? HWC_DISPLAY_PRIMARY
- : HWC_DISPLAY_EXTERNAL);
+ ? LEGACY_DISPLAY_TYPE_PRIMARY
+ : LEGACY_DISPLAY_TYPE_EXTERNAL);
}
const auto info =
@@ -317,6 +371,33 @@
static std::optional<DisplayId> get() { return {}; }
};
+template <typename>
+struct DisplayConnectionTypeGetter {
+ static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+};
+
+template <typename>
+struct HwcDisplayIdGetter {
+ static constexpr std::optional<HWDisplayId> value;
+};
+
+constexpr HWDisplayId HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID = 1010;
+
+template <DisplayId::Type displayId>
+struct HwcDisplayIdGetter<VirtualDisplayId<displayId>> {
+ static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID;
+};
+
+template <typename PhysicalDisplay>
+struct HwcDisplayIdGetter<PhysicalDisplayId<PhysicalDisplay>> {
+ static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
+};
+
// DisplayIdType can be:
// 1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
// 2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
@@ -325,6 +406,8 @@
Secure secure, Primary primary, int grallocUsage>
struct DisplayVariant {
using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+ using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
+ using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>;
// The display width and height
static constexpr int WIDTH = width;
@@ -349,9 +432,21 @@
static constexpr Primary PRIMARY = primary;
static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
- auto injector =
- FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
- static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
+ if (auto displayId = DISPLAY_ID::get()) {
+ ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
+ } else {
+ ceDisplayArgs.setUseHwcVirtualDisplays(false);
+ }
+ ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor).build();
+
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs.build());
+
+ auto injector = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
+ CONNECTION_TYPE::value, HWC_DISPLAY_ID_OPT::value,
+ static_cast<bool>(PRIMARY));
injector.setSecure(static_cast<bool>(SECURE));
injector.setNativeWindow(test->mNativeWindow);
@@ -409,21 +504,20 @@
}
};
-template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant,
+template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant,
typename PhysicalDisplay = void>
struct HwcDisplayVariant {
// The display id supplied by the HWC
- static constexpr hwc2_display_t HWC_DISPLAY_ID = hwcDisplayId;
+ static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId;
// The HWC display type
- static constexpr HWC2::DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
+ static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
// The HWC active configuration id
static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
- static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+ static constexpr PowerMode INIT_POWER_MODE = PowerMode::ON;
- static void injectPendingHotplugEvent(DisplayTransactionTest* test,
- HWC2::Connection connection) {
+ static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
test->mFlinger.mutablePendingHotplugEvents().emplace_back(
HotplugEvent{HWC_DISPLAY_ID, connection});
}
@@ -445,21 +539,43 @@
// Called by tests to inject a HWC display setup
static void injectHwcDisplay(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer,
- setPowerMode(HWC_DISPLAY_ID,
- static_cast<Hwc2::IComposerClient::PowerMode>(INIT_POWER_MODE)))
+ EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
.WillOnce(Return(Error::NONE));
injectHwcDisplayWithNoDefaultCapabilities(test);
}
+ static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+ DisplayTransactionTest* test) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+ .setPhysical({*DisplayVariant::DISPLAY_ID::get(),
+ PhysicalDisplay::CONNECTION_TYPE})
+ .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
+ .setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
+ .setPowerAdvisor(&test->mPowerAdvisor)
+ .setName(std::string("Injected display for ") +
+ test_info->test_case_name() + "." + test_info->name())
+ .build();
+
+ return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs);
+ }
+
static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
- EXPECT_CALL(*test->mComposer, getDisplayType(HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(static_cast<IComposerClient::DisplayType>(
- HWC_DISPLAY_TYPE)),
- Return(Error::NONE)));
- EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
+ constexpr auto CONNECTION_TYPE =
+ PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+ ? IComposerClient::DisplayConnectionType::INTERNAL
+ : IComposerClient::DisplayConnectionType::EXTERNAL;
+
+ EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
+ .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(hal::V2_4::Error::NONE)));
+
+ EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
+ .WillOnce(Return(hal::Error::NONE));
EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
.WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
Return(Error::NONE)));
@@ -483,6 +599,10 @@
getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
IComposerClient::Attribute::DPI_Y, _))
.WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+ EXPECT_CALL(*test->mComposer,
+ getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+ IComposerClient::Attribute::CONFIG_GROUP, _))
+ .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -506,12 +626,11 @@
constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-template <hwc2_display_t hwcDisplayId, typename PhysicalDisplay, int width, int height,
- Critical critical>
+template <typename PhysicalDisplay, int width, int height, Critical critical>
struct PhysicalDisplayVariant
: DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height, critical, Async::FALSE,
Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
- HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
+ HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height,
critical, Async::FALSE, Secure::TRUE,
PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
@@ -519,16 +638,20 @@
template <bool hasIdentificationData>
struct PrimaryDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
static constexpr Primary PRIMARY = Primary::TRUE;
static constexpr uint8_t PORT = 255;
+ static constexpr HWDisplayId HWC_DISPLAY_ID = 1001;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
};
template <bool hasIdentificationData>
struct ExternalDisplay {
+ static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 254;
+ static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
};
@@ -536,19 +659,19 @@
struct TertiaryDisplay {
static constexpr Primary PRIMARY = Primary::FALSE;
static constexpr uint8_t PORT = 253;
+ static constexpr HWDisplayId HWC_DISPLAY_ID = 1003;
static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
};
// A primary display is a physical display that is critical
using PrimaryDisplayVariant =
- PhysicalDisplayVariant<1001, PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
+ PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
// An external display is physical display that is not critical.
using ExternalDisplayVariant =
- PhysicalDisplayVariant<1002, ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
+ PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
-using TertiaryDisplayVariant =
- PhysicalDisplayVariant<1003, TertiaryDisplay, 1600, 1200, Critical::FALSE>;
+using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200, Critical::FALSE>;
// A virtual display not supported by the HWC.
constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
@@ -562,6 +685,23 @@
static void injectHwcDisplay(DisplayTransactionTest*) {}
+ static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+ DisplayTransactionTest* test) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+ .setPixels({Base::WIDTH, Base::HEIGHT})
+ .setIsSecure(static_cast<bool>(Base::SECURE))
+ .setPowerAdvisor(&test->mPowerAdvisor)
+ .setName(std::string("Injected display for ") +
+ test_info->test_case_name() + "." + test_info->name())
+ .build();
+
+ return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs);
+ }
+
static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
}
@@ -580,13 +720,40 @@
: DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE, secure,
Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
HwcDisplayVariant<
- 1010, HWC2::DisplayType::Virtual,
+ HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
using Base = DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
using Self = HwcVirtualDisplayVariant<width, height, secure>;
+ static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+ DisplayTransactionTest* test) {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+
+ auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+ .setUseHwcVirtualDisplays(false)
+ .setPixels({Base::WIDTH, Base::HEIGHT})
+ .setIsSecure(static_cast<bool>(Base::SECURE))
+ .setPowerAdvisor(&test->mPowerAdvisor)
+ .setName(std::string("Injected display for ") +
+ test_info->test_case_name() + "." + test_info->name())
+ .build();
+
+ auto compositionDisplay =
+ compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+ ceDisplayArgs);
+ compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get());
+
+ // Insert display data so that the HWC thinks it created the virtual display.
+ if (const auto displayId = Base::DISPLAY_ID::get()) {
+ test->mFlinger.mutableHwcDisplayData().try_emplace(*displayId);
+ }
+
+ return compositionDisplay;
+ }
+
static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
Base::setupNativeWindowSurfaceCreationCallExpectations(test);
EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
@@ -608,7 +775,7 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableHasWideColorDisplay() = false;
test->mFlinger.mutableUseColorManagement() = false;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -628,7 +795,7 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableUseColorManagement() = true;
test->mFlinger.mutableHasWideColorDisplay() = true;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -883,8 +1050,8 @@
TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
constexpr int currentSequenceId = 123;
- constexpr hwc2_display_t hwcDisplayId1 = 456;
- constexpr hwc2_display_t hwcDisplayId2 = 654;
+ constexpr HWDisplayId hwcDisplayId1 = 456;
+ constexpr HWDisplayId hwcDisplayId2 = 654;
// --------------------------------------------------------------------
// Preconditions
@@ -907,8 +1074,8 @@
// Invocation
// Simulate two hotplug events (a connect and a disconnect)
- mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, HWC2::Connection::Connected);
- mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, HWC2::Connection::Disconnected);
+ mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, Connection::CONNECTED);
+ mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, Connection::DISCONNECTED);
// --------------------------------------------------------------------
// Postconditions
@@ -920,15 +1087,15 @@
const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
ASSERT_EQ(2u, pendingEvents.size());
EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
- EXPECT_EQ(HWC2::Connection::Connected, pendingEvents[0].connection);
+ EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection);
EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
- EXPECT_EQ(HWC2::Connection::Disconnected, pendingEvents[1].connection);
+ EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection);
}
TEST_F(DisplayTransactionTest, hotplugDiscardsUnexpectedEvents) {
constexpr int currentSequenceId = 123;
constexpr int otherSequenceId = 321;
- constexpr hwc2_display_t displayId = 456;
+ constexpr HWDisplayId displayId = 456;
// --------------------------------------------------------------------
// Preconditions
@@ -950,7 +1117,7 @@
// Invocation
// Call with an unexpected sequence id
- mFlinger.onHotplugReceived(otherSequenceId, displayId, HWC2::Connection::Invalid);
+ mFlinger.onHotplugReceived(otherSequenceId, displayId, Connection::INVALID);
// --------------------------------------------------------------------
// Postconditions
@@ -964,7 +1131,7 @@
TEST_F(DisplayTransactionTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) {
constexpr int currentSequenceId = 123;
- constexpr hwc2_display_t displayId1 = 456;
+ constexpr HWDisplayId displayId1 = 456;
// --------------------------------------------------------------------
// Note:
@@ -998,7 +1165,7 @@
// Simulate a disconnect on a display id that is not connected. This should
// be enqueued by onHotplugReceived(), and dequeued by
// processDisplayHotplugEventsLocked(), but then ignored as invalid.
- mFlinger.onHotplugReceived(currentSequenceId, displayId1, HWC2::Connection::Disconnected);
+ mFlinger.onHotplugReceived(currentSequenceId, displayId1, Connection::DISCONNECTED);
// --------------------------------------------------------------------
// Postconditions
@@ -1141,8 +1308,8 @@
// Preconditions
// vsync is enabled and available
- mScheduler->mutablePrimaryHWVsyncEnabled() = true;
- mScheduler->mutableHWVsyncAvailable() = true;
+ mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true;
+ mFlinger.scheduler()->mutableHWVsyncAvailable() = true;
// A display exists
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
@@ -1166,8 +1333,8 @@
// Postconditions
// vsyncs should be off and not available.
- EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled());
- EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable());
+ EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled());
+ EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable());
// The display should have been removed from the display map.
EXPECT_FALSE(hasDisplayDevice(existing.token()));
@@ -1184,13 +1351,6 @@
*/
class GetBestColorModeTest : public DisplayTransactionTest {
public:
- static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
-
- GetBestColorModeTest()
- : DisplayTransactionTest(),
- mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
- true /* isPrimary */)) {}
-
void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
void addHwcColorModesMapping(ui::ColorMode colorMode,
@@ -1203,21 +1363,12 @@
void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
void getBestColorMode() {
- mInjector.setHwcColorModes(mHwcColorModes);
- mInjector.setHasWideColorGamut(mHasWideColorGamut);
- mInjector.setNativeWindow(mNativeWindow);
-
- // Creating a DisplayDevice requires getting default dimensions from the
- // native window.
- EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
- EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
- EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
- auto displayDevice = mInjector.inject();
+ auto displayDevice =
+ injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
+ injector.setHwcColorModes(mHwcColorModes);
+ injector.setHasWideColorGamut(mHasWideColorGamut);
+ injector.setNativeWindow(mNativeWindow);
+ });
displayDevice->getCompositionDisplay()
->getDisplayColorProfile()
@@ -1234,7 +1385,6 @@
ui::RenderIntent mInputRenderIntent;
bool mHasWideColorGamut = false;
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
- FakeDisplayDeviceInjector mInjector;
};
TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
@@ -1284,6 +1434,230 @@
}
/* ------------------------------------------------------------------------
+ * DisplayDevice::setProjection
+ */
+
+class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
+public:
+ static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080; // arbitrary
+ static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
+
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_0 = 0;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_90 = HAL_TRANSFORM_ROT_90;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_180 = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V;
+ static constexpr int32_t TRANSFORM_FLAGS_ROT_270 =
+ HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+
+ DisplayDeviceSetProjectionTest(ui::Size flingerDisplaySize, ui::Size hardwareDisplaySize,
+ ui::Rotation physicalOrientation)
+ : mFlingerDisplaySize(flingerDisplaySize),
+ mHardwareDisplaySize(hardwareDisplaySize),
+ mPhysicalOrientation(physicalOrientation),
+ mDisplayDevice(createDisplayDevice()) {}
+
+ sp<DisplayDevice> createDisplayDevice() {
+ return injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
+ injector.setPhysicalOrientation(mPhysicalOrientation);
+ });
+ }
+
+ ui::Size SwapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
+
+ void setProjectionForRotation0() {
+ // A logical rotation of 0 uses the SurfaceFlinger display size
+ mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize),
+ Rect(mFlingerDisplaySize));
+ }
+
+ void setProjectionForRotation90() {
+ // A logical rotation of 90 uses the SurfaceFlinger display size with
+ // the width/height swapped.
+ mDisplayDevice->setProjection(ui::ROTATION_90, Rect(SwapWH(mFlingerDisplaySize)),
+ Rect(SwapWH(mFlingerDisplaySize)));
+ }
+
+ void setProjectionForRotation180() {
+ // A logical rotation of 180 uses the SurfaceFlinger display size
+ mDisplayDevice->setProjection(ui::ROTATION_180, Rect(mFlingerDisplaySize),
+ Rect(mFlingerDisplaySize));
+ }
+
+ void setProjectionForRotation270() {
+ // A logical rotation of 270 uses the SurfaceFlinger display size with
+ // the width/height swapped.
+ mDisplayDevice->setProjection(ui::ROTATION_270, Rect(SwapWH(mFlingerDisplaySize)),
+ Rect(SwapWH(mFlingerDisplaySize)));
+ }
+
+ void expectStateForHardwareTransform0() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform90() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+ // For 90, the frame and viewport have the hardware display size width and height swapped
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform180() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ void expectStateForHardwareTransform270() {
+ const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+ EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
+ mHardwareDisplaySize.height),
+ compositionState.transform);
+ EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+ // For 270, the frame and viewport have the hardware display size width and height swapped
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+ EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+ EXPECT_EQ(false, compositionState.needsFiltering);
+ }
+
+ const ui::Size mFlingerDisplaySize;
+ const ui::Size mHardwareDisplaySize;
+ const ui::Rotation mPhysicalOrientation;
+ const sp<DisplayDevice> mDisplayDevice;
+};
+
+struct DisplayDeviceSetProjectionTest_Installed0 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed0()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_0) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform270();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed90 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed90()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_90) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform0();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed180 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed180()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_180) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform90();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed270 : public DisplayDeviceSetProjectionTest {
+ DisplayDeviceSetProjectionTest_Installed270()
+ : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+ ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+ ui::ROTATION_270) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) {
+ setProjectionForRotation0();
+ expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith90OutputRotation) {
+ setProjectionForRotation90();
+ expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith180OutputRotation) {
+ setProjectionForRotation180();
+ expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith270OutputRotation) {
+ setProjectionForRotation270();
+ expectStateForHardwareTransform180();
+}
+
+/* ------------------------------------------------------------------------
* SurfaceFlinger::getDisplayNativePrimaries
*/
@@ -1361,7 +1735,8 @@
ui::DisplayPrimaries primaries;
populateDummyDisplayNativePrimaries(primaries);
- EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
+ EXPECT_EQ(NAME_NOT_FOUND,
+ mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
// Check primaries argument wasn't modified in case of failure
checkDummyDisplayNativePrimaries(primaries);
@@ -1397,6 +1772,9 @@
// surfaces.
injectFakeNativeWindowSurfaceFactory();
+ // A compositionengine::Display has already been created
+ auto compositionDisplay = Case::Display::injectCompositionDisplay(this);
+
// --------------------------------------------------------------------
// Call Expectations
@@ -1411,19 +1789,25 @@
// Invocation
DisplayDeviceState state;
- state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get();
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+ ASSERT_TRUE(hwcDisplayId);
+ state.physical = {*displayId, *connectionType, *hwcDisplayId};
+ }
+
state.isSecure = static_cast<bool>(Case::Display::SECURE);
- auto device =
- mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(),
- state, displaySurface, producer);
+ auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
+ displaySurface, producer);
// --------------------------------------------------------------------
// Postconditions
ASSERT_TRUE(device != nullptr);
EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+ EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
@@ -1437,7 +1821,7 @@
// Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
// remapped, and the test only ever sets up one config. If there were an error
// looking up the remapped index, device->getActiveConfig() would be -1 instead.
- EXPECT_EQ(0, device->getActiveConfig());
+ EXPECT_EQ(0, device->getActiveConfig().value());
EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
device->getSupportedPerFrameMetadata());
}
@@ -1455,14 +1839,7 @@
}
TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
- using Case = HwcVirtualDisplayCase;
-
- // Insert display data so that the HWC thinks it created the virtual display.
- const auto displayId = Case::Display::DISPLAY_ID::get();
- ASSERT_TRUE(displayId);
- mFlinger.mutableHwcDisplayData().try_emplace(*displayId);
-
- setupNewDisplayDeviceInternalTest<Case>();
+ setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
}
TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
@@ -1587,21 +1964,26 @@
EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
+ std::optional<DisplayDeviceState::Physical> expectedPhysical;
+ if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+ const auto displayId = Case::Display::DISPLAY_ID::get();
+ ASSERT_TRUE(displayId);
+ const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+ ASSERT_TRUE(hwcDisplayId);
+ expectedPhysical = {*displayId, *connectionType, *hwcDisplayId};
+ }
+
// The display should have been set up in the current display state
ASSERT_TRUE(hasCurrentDisplayState(displayToken));
const auto& current = getCurrentDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- current.displayId);
+ EXPECT_EQ(expectedPhysical, current.physical);
// The display should have been set up in the drawing display state
ASSERT_TRUE(hasDrawingDisplayState(displayToken));
const auto& draw = getDrawingDisplayState(displayToken);
EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
- EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
- : Case::Display::DISPLAY_ID::get(),
- draw.displayId);
+ EXPECT_EQ(expectedPhysical, draw.physical);
}
template <typename Case>
@@ -1632,7 +2014,7 @@
setupCommonPreconditions<Case>();
// A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// --------------------------------------------------------------------
// Call Expectations
@@ -1668,7 +2050,7 @@
setupCommonPreconditions<Case>();
// A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// --------------------------------------------------------------------
// Invocation
@@ -1690,7 +2072,7 @@
setupCommonPreconditions<Case>();
// A hotplug disconnect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
// The display is already completely set up.
Case::Display::injectHwcDisplay(this);
@@ -1771,11 +2153,11 @@
ignoresHotplugConnectCommon<SimpleExternalDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processHotplugDisconnectPrimaryDisplay) {
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
}
-TEST_F(HandleTransactionLockedTest, processHotplugDisconnectExternalDisplay) {
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
}
@@ -1788,9 +2170,9 @@
setupCommonPreconditions<Case>();
// A hotplug connect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// A hotplug disconnect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
// --------------------------------------------------------------------
// Call Expectations
@@ -1836,9 +2218,9 @@
existing.inject();
// A hotplug disconnect event is enqueued for a display
- Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+ Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
// A hotplug connect event is also enqueued for the same display
- Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+ Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
// --------------------------------------------------------------------
// Call Expectations
@@ -2050,8 +2432,8 @@
TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
using Case = NonHwcVirtualDisplayCase;
- constexpr int oldTransform = 0;
- constexpr int newTransform = 2;
+ constexpr ui::Rotation oldTransform = ui::ROTATION_0;
+ constexpr ui::Rotation newTransform = ui::ROTATION_180;
// --------------------------------------------------------------------
// Preconditions
@@ -2424,7 +2806,7 @@
TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
using Case = SimplePrimaryDisplayCase;
- constexpr int initialOrientation = 180;
+ constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
const Rect initialFrame = {1, 2, 3, 4};
const Rect initialViewport = {5, 6, 7, 8};
@@ -2468,8 +2850,8 @@
TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
using Case = SimplePrimaryDisplayCase;
- constexpr int initialOrientation = 90;
- constexpr int desiredOrientation = 180;
+ constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
+ constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
// --------------------------------------------------------------------
// Preconditions
@@ -2715,7 +3097,7 @@
// processing.
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
- EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
// --------------------------------------------------------------------
// Invocation
@@ -2731,7 +3113,7 @@
// The layer stack state should be set to zero
EXPECT_EQ(0u, primaryDisplayState.layerStack);
// The orientation state should be set to zero
- EXPECT_EQ(0, primaryDisplayState.orientation);
+ EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
// The frame state should be set to INVALID
EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.frame);
@@ -2743,10 +3125,10 @@
EXPECT_EQ(0u, primaryDisplayState.width);
EXPECT_EQ(0u, primaryDisplayState.height);
- // The display should be set to HWC_POWER_MODE_NORMAL
+ // The display should be set to PowerMode::ON
ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
auto displayDevice = primaryDisplay.mutableDisplayDevice();
- EXPECT_EQ(HWC_POWER_MODE_NORMAL, displayDevice->getPowerMode());
+ EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
// The display refresh period should be set in the frame tracker.
FrameStats stats;
@@ -2778,8 +3160,8 @@
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>(
- {Hwc2::DisplayCapability::DOZE})),
+ .WillOnce(DoAll(SetArgPointee<1>(
+ std::vector<DisplayCapability>({DisplayCapability::DOZE})),
Return(Error::NONE)));
}
};
@@ -2795,7 +3177,7 @@
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
- .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
Return(Error::NONE)));
}
};
@@ -2869,7 +3251,7 @@
// selected subset which provides complete test coverage of the implementation.
// --------------------------------------------------------------------
-template <int initialPowerMode, int targetPowerMode>
+template <PowerMode initialPowerMode, PowerMode targetPowerMode>
struct TransitionVariantCommon {
static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
static constexpr auto TARGET_POWER_MODE = targetPowerMode;
@@ -2877,8 +3259,7 @@
static void verifyPostconditions(DisplayTransactionTest*) {}
};
-struct TransitionOffToOnVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_NORMAL> {
+struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, PowerMode::ON> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
@@ -2894,7 +3275,7 @@
};
struct TransitionOffToDozeSuspendVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_DOZE_SUSPEND> {
+ : public TransitionVariantCommon<PowerMode::OFF, PowerMode::DOZE_SUSPEND> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
@@ -2908,8 +3289,7 @@
}
};
-struct TransitionOnToOffVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_OFF> {
+struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
@@ -2923,7 +3303,7 @@
};
struct TransitionDozeSuspendToOffVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_OFF> {
+ : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -2935,8 +3315,7 @@
}
};
-struct TransitionOnToDozeVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE> {
+struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -2945,7 +3324,7 @@
};
struct TransitionDozeSuspendToDozeVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_DOZE> {
+ : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
@@ -2954,8 +3333,7 @@
}
};
-struct TransitionDozeToOnVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_DOZE, HWC_POWER_MODE_NORMAL> {
+struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -2964,7 +3342,7 @@
};
struct TransitionDozeSuspendToOnVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_NORMAL> {
+ : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
@@ -2974,7 +3352,7 @@
};
struct TransitionOnToDozeSuspendVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE_SUSPEND> {
+ : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
@@ -2984,7 +3362,7 @@
};
struct TransitionOnToUnknownVariant
- : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_LEET> {
+ : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
template <typename Case>
static void setupCallExpectations(DisplayTransactionTest* test) {
Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -3009,7 +3387,7 @@
using DispSync = DispSyncVariant;
using Transition = TransitionVariant;
- static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
+ static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
Display::injectHwcDisplayWithNoDefaultCapabilities(test);
auto display = Display::makeFakeExistingDisplayInjector(test);
display.inject();
@@ -3018,20 +3396,21 @@
}
static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
- test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled;
+ test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
}
static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
}
- static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test, int mode) {
+ static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
+ PowerMode mode) {
EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
- EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, mode)).Times(1);
+ EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
+ .Times(1);
}
- static void setupComposerCallExpectations(DisplayTransactionTest* test,
- IComposerClient::PowerMode mode) {
+ static void setupComposerCallExpectations(DisplayTransactionTest* test, PowerMode mode) {
// Any calls to get the active config will return a default value.
EXPECT_CALL(*test->mComposer, getActiveConfig(Display::HWC_DISPLAY_ID, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(Display::HWC_ACTIVE_CONFIG_ID),
@@ -3073,14 +3452,14 @@
void transitionDisplayCommon();
};
-template <int PowerMode>
+template <PowerMode PowerMode>
struct PowerModeInitialVSyncEnabled : public std::false_type {};
template <>
-struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_NORMAL> : public std::true_type {};
+struct PowerModeInitialVSyncEnabled<PowerMode::ON> : public std::true_type {};
template <>
-struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_DOZE> : public std::true_type {};
+struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
template <typename Case>
void SetPowerModeInternalTest::transitionDisplayCommon() {
@@ -3123,18 +3502,18 @@
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
- // The display is already set to HWC_POWER_MODE_NORMAL
- display.mutableDisplayDevice()->setPowerMode(HWC_POWER_MODE_NORMAL);
+ // The display is already set to PowerMode::ON
+ display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_NORMAL);
+ mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
// --------------------------------------------------------------------
// Postconditions
- EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+ EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
}
TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
@@ -3153,18 +3532,18 @@
auto display = Case::Display::makeFakeExistingDisplayInjector(this);
display.inject();
- // The display is set to HWC_POWER_MODE_NORMAL
- getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_NORMAL);
+ // The display is set to PowerMode::ON
+ getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
// --------------------------------------------------------------------
// Invocation
- mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_OFF);
+ mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
// --------------------------------------------------------------------
// Postconditions
- EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+ EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
}
TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
@@ -3249,3 +3628,6 @@
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index dbd9b84..b90b566 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -19,13 +19,12 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
-
#include <utils/Errors.h>
#include "AsyncCallRecorder.h"
#include "Scheduler/EventThread.h"
+#include "Scheduler/HwcStrongTypes.h"
using namespace std::chrono_literals;
using namespace std::placeholders;
@@ -34,6 +33,7 @@
using testing::Invoke;
namespace android {
+
namespace {
constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111;
@@ -42,10 +42,13 @@
class MockVSyncSource : public VSyncSource {
public:
+ const char* getName() const override { return "test"; }
+
MOCK_METHOD1(setVSyncEnabled, void(bool));
MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
MOCK_METHOD1(pauseVsyncCallback, void(bool));
+ MOCK_CONST_METHOD1(dump, void(std::string&));
};
} // namespace
@@ -54,8 +57,7 @@
protected:
class MockEventThreadConnection : public EventThreadConnection {
public:
- MockEventThreadConnection(android::impl::EventThread* eventThread,
- ResyncCallback&& resyncCallback,
+ MockEventThreadConnection(impl::EventThread* eventThread, ResyncCallback&& resyncCallback,
ISurfaceComposer::ConfigChanged configChanged)
: EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
@@ -67,7 +69,7 @@
EventThreadTest();
~EventThreadTest() override;
- void createThread();
+ void createThread(std::unique_ptr<VSyncSource>);
sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
ISurfaceComposer::ConfigChanged configChanged);
@@ -82,7 +84,8 @@
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
- int32_t expectedConfigId);
+ int32_t expectedConfigId,
+ nsecs_t expectedVsyncPeriod);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -91,9 +94,9 @@
AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
- MockVSyncSource mVSyncSource;
+ MockVSyncSource* mVSyncSource;
VSyncSource::Callback* mCallback = nullptr;
- std::unique_ptr<android::impl::EventThread> mThread;
+ std::unique_ptr<impl::EventThread> mThread;
sp<MockEventThreadConnection> mConnection;
};
@@ -102,16 +105,19 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- EXPECT_CALL(mVSyncSource, setVSyncEnabled(_))
+ auto vsyncSource = std::make_unique<MockVSyncSource>();
+ mVSyncSource = vsyncSource.get();
+
+ EXPECT_CALL(*mVSyncSource, setVSyncEnabled(_))
.WillRepeatedly(Invoke(mVSyncSetEnabledCallRecorder.getInvocable()));
- EXPECT_CALL(mVSyncSource, setCallback(_))
+ EXPECT_CALL(*mVSyncSource, setCallback(_))
.WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
- EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
+ EXPECT_CALL(*mVSyncSource, setPhaseOffset(_))
.WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
- createThread();
+ createThread(std::move(vsyncSource));
mConnection = createConnection(mConnectionEventCallRecorder,
ISurfaceComposer::eConfigChangedDispatch);
@@ -129,11 +135,9 @@
EXPECT_TRUE(!mVSyncSetCallbackCallRecorder.waitForUnexpectedCall().has_value());
}
-void EventThreadTest::createThread() {
- mThread =
- std::make_unique<android::impl::EventThread>(&mVSyncSource,
- mInterceptVSyncCallRecorder.getInvocable(),
- "unit-test-event-thread");
+void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) {
+ mThread = std::make_unique<impl::EventThread>(std::move(source),
+ mInterceptVSyncCallRecorder.getInvocable());
// EventThread should register itself as VSyncSource callback.
mCallback = expectVSyncSetCallbackCallReceived();
@@ -205,13 +209,15 @@
}
void EventThreadTest::expectConfigChangedEventReceivedByConnection(
- PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) {
+ PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId,
+ nsecs_t expectedVsyncPeriod) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(expectedConfigId, event.config.configId);
+ EXPECT_EQ(expectedVsyncPeriod, event.config.vsyncPeriod);
}
namespace {
@@ -252,14 +258,14 @@
// Use the received callback to signal a first vsync event.
// The interceptor should receive the event, as well as the connection.
- mCallback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123, 456);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// Use the received callback to signal a second vsync event.
// The interceptor should receive the event, but the the connection should
// not as it was only interested in the first.
- mCallback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456, 123);
expectInterceptCallReceived(456);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -293,7 +299,7 @@
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the second connection. The first connection should not
// get the event.
- mCallback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123, 456);
expectInterceptCallReceived(123);
EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -308,17 +314,17 @@
// Send a vsync event. EventThread should then make a call to the
// interceptor, and the connection.
- mCallback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123, 456);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection(123, 1u);
// A second event should go to the same places.
- mCallback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456, 123);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// A third event should go to the same places.
- mCallback->onVSyncEvent(789);
+ mCallback->onVSyncEvent(789, 777);
expectInterceptCallReceived(789);
expectVsyncEventReceivedByConnection(789, 3u);
}
@@ -330,22 +336,22 @@
expectVSyncSetEnabledCallReceived(true);
// The first event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123, 456);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The second event will be seen by the interceptor and the connection.
- mCallback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456, 123);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection(456, 2u);
// The third event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(789);
+ mCallback->onVSyncEvent(789, 777);
expectInterceptCallReceived(789);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
// The fourth event will be seen by the interceptor and the connection.
- mCallback->onVSyncEvent(101112);
+ mCallback->onVSyncEvent(101112, 7847);
expectInterceptCallReceived(101112);
expectVsyncEventReceivedByConnection(101112, 4u);
}
@@ -360,7 +366,7 @@
mConnection = nullptr;
// The first event will be seen by the interceptor, and not the connection.
- mCallback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123, 456);
expectInterceptCallReceived(123);
EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
@@ -380,13 +386,13 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an error.
- mCallback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123, 456);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor and not by the
// connection.
- mCallback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456, 123);
expectInterceptCallReceived(456);
EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
@@ -394,6 +400,34 @@
expectVSyncSetEnabledCallReceived(false);
}
+TEST_F(EventThreadTest, tracksEventConnections) {
+ EXPECT_EQ(1, mThread->getEventThreadConnectionCount());
+ ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
+ sp<MockEventThreadConnection> errorConnection =
+ createConnection(errorConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+ mThread->setVsyncRate(1, errorConnection);
+ EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+ ConnectionEventRecorder secondConnectionEventRecorder{0};
+ sp<MockEventThreadConnection> secondConnection =
+ createConnection(secondConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+ mThread->setVsyncRate(1, secondConnection);
+ EXPECT_EQ(3, mThread->getEventThreadConnectionCount());
+
+ // EventThread should enable vsync callbacks.
+ expectVSyncSetEnabledCallReceived(true);
+
+ // The first event will be seen by the interceptor, and by the connection,
+ // which then returns an error.
+ mCallback->onVSyncEvent(123, 456);
+ expectInterceptCallReceived(123);
+ expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+ expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
+ 1u);
+ EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+}
+
TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
sp<MockEventThreadConnection> errorConnection =
@@ -406,13 +440,13 @@
// The first event will be seen by the interceptor, and by the connection,
// which then returns an non-fatal error.
- mCallback->onVSyncEvent(123);
+ mCallback->onVSyncEvent(123, 456);
expectInterceptCallReceived(123);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
// A subsequent event will be seen by the interceptor, and by the connection,
// which still then returns an non-fatal error.
- mCallback->onVSyncEvent(456);
+ mCallback->onVSyncEvent(456, 123);
expectInterceptCallReceived(456);
expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
@@ -446,18 +480,18 @@
}
TEST_F(EventThreadTest, postConfigChangedPrimary) {
- mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 7);
- expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7);
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7), 16666666);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedExternal) {
- mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, 5);
- expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
+ mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5), 16666666);
+ expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
- mThread->onConfigChanged(DISPLAY_ID_64BIT, 7);
- expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
+ mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7), 16666666);
+ expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
}
TEST_F(EventThreadTest, suppressConfigChanged) {
@@ -466,8 +500,8 @@
createConnection(suppressConnectionEventRecorder,
ISurfaceComposer::eConfigChangedSuppress);
- mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9);
- expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9), 16666666);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
auto args = suppressConnectionEventRecorder.waitForCall();
ASSERT_FALSE(args.has_value());
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 1d75011..b50ddf5 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -20,42 +20,21 @@
#include "Scheduler/PhaseOffsets.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+struct FakePhaseOffsets : PhaseConfiguration {
+ static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
-class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
- nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+ Offsets getOffsetsForRefreshRate(float) const override { return getCurrentOffsets(); }
-public:
- FakePhaseOffsets() = default;
- ~FakePhaseOffsets() = default;
-
- nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
- nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
-
- PhaseOffsets::Offsets getOffsetsForRefreshRate(
- RefreshRateType /*refreshRateType*/) const override {
- return getCurrentOffsets();
+ Offsets getCurrentOffsets() const override {
+ return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
}
- // Returns early, early GL, and late offsets for Apps and SF.
- PhaseOffsets::Offsets getCurrentOffsets() const override {
- return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
- }
-
- // This function should be called when the device is switching between different
- // refresh rates, to properly update the offsets.
- void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {}
-
- nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
-
- // Returns current offsets in human friendly format.
- void dump(std::string& /*result*/) const override {}
+ void setRefreshRateFps(float) override {}
+ void dump(std::string&) const override {}
};
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
new file mode 100644
index 0000000..a119e27
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <FrameTracer/FrameTracer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <perfetto/trace/trace.pb.h>
+
+#include "libsurfaceflinger_unittest_main.h"
+
+using namespace google::protobuf;
+
+namespace android {
+namespace {
+
+class FrameTracerTest : public testing::Test {
+public:
+ FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // Need to initialize tracing in process for testing, and only once per test suite.
+ static bool wasInitialized = false;
+ if (!wasInitialized) {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kInProcessBackend;
+ perfetto::Tracing::Initialize(args);
+ wasInitialized = true;
+ }
+ }
+
+ ~FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void SetUp() override {
+ mFrameTracer = std::make_unique<FrameTracer>();
+ mFrameTracer->registerDataSource();
+ }
+
+ void TearDown() override { mFrameTracer.reset(); }
+
+ // Each tracing session can be used for a single block of Start -> Stop.
+ static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name(FrameTracer::kFrameTracerDataSource);
+
+ auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+ tracingSession->Setup(cfg);
+ return tracingSession;
+ }
+
+ std::vector<perfetto::protos::TracePacket> readGraphicsFramePacketsBlocking(
+ perfetto::TracingSession* tracingSession) {
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ perfetto::protos::Trace trace;
+ EXPECT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+
+ std::vector<perfetto::protos::TracePacket> packets;
+ for (const auto& packet : trace.packet()) {
+ if (!packet.has_graphics_frame_event()) {
+ continue;
+ }
+ packets.emplace_back(packet);
+ }
+ return packets;
+ }
+
+ std::unique_ptr<FrameTracer> mFrameTracer;
+ FenceToFenceTimeMap fenceFactory;
+};
+
+TEST_F(FrameTracerTest, traceNewLayerStartsTrackingLayerWhenTracing) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerId = 5;
+ mFrameTracer->traceNewLayer(layerId, layerName);
+
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+ mFrameTracer->traceNewLayer(layerId, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ tracingSession->StopBlocking();
+}
+
+TEST_F(FrameTracerTest, onDestroyRemovesTheTrackedLayer) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerId = 5;
+ const int32_t secondlayerId = 6;
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerId, layerName);
+ mFrameTracer->traceNewLayer(secondlayerId, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 2\n");
+ tracingSession->StopBlocking();
+
+ mFrameTracer->onDestroy(layerId);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(layerId);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(secondlayerId);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+}
+
+TEST_F(FrameTracerTest, canTraceAfterAddingLayer) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerId = 1;
+ const uint32_t bufferID = 2;
+ const uint64_t frameNumber = 3;
+ const nsecs_t timestamp = 4;
+ const nsecs_t duration = 5;
+ const auto type = FrameTracer::FrameEvent::POST;
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+ EXPECT_EQ(packets.size(), 0);
+ }
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerId, layerName);
+ mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+ EXPECT_EQ(packets.size(), 1);
+
+ const auto& packet = packets[0];
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ ASSERT_TRUE(buffer_event.has_duration_ns());
+ EXPECT_EQ(buffer_event.duration_ns(), duration);
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerId = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Trace.
+ mFrameTracer->traceNewLayer(layerId, layerName);
+ mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type);
+ // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
+ mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+ EXPECT_EQ(packets.size(), 0);
+ }
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerId, layerName);
+ mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type);
+ const nsecs_t timestamp = systemTime();
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+ EXPECT_EQ(packets.size(), 2); // Two packets because of the extra trace made above.
+
+ const auto& packet = packets[1];
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ EXPECT_FALSE(buffer_event.has_duration_ns());
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerId = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerId, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 + 100000;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 + 100000;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+ EXPECT_EQ(packets.size(), 2);
+
+ const auto& packet1 = packets[0];
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), signalTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+
+ const auto& packet2 = packets[1];
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), signalTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+}
+
+TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerId = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t signalTime = systemTime() - FrameTracer::kFenceSignallingDeadline;
+
+ auto tracingSession = getTracingSessionForTest();
+ auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerId, layerName);
+ mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence, type);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
+ // Create extra trace packet to trigger and finalize any previous fence packets.
+ mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+ EXPECT_EQ(packets.size(), 0);
+}
+
+TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerId = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t duration = 1234;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerId, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 - duration;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 - duration;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+ EXPECT_EQ(packets.size(), 2);
+
+ const auto& packet1 = packets[0];
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), startTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event1.duration_ns(), duration);
+
+ const auto& packet2 = packets[1];
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), startTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event2.duration_ns(), duration);
+}
+
+} // namespace
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
new file mode 100644
index 0000000..91b304c
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2020 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gui/LayerMetadata.h>
+#include <log/log.h>
+
+#include "DisplayHardware/HWComposer.h"
+#include "mock/DisplayHardware/MockComposer.h"
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
+namespace android {
+namespace {
+
+namespace hal = android::hardware::graphics::composer::hal;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
+struct MockHWC2ComposerCallback : public HWC2::ComposerCallback {
+ ~MockHWC2ComposerCallback() = default;
+
+ MOCK_METHOD3(onHotplugReceived,
+ void(int32_t sequenceId, hal::HWDisplayId display, hal::Connection connection));
+ MOCK_METHOD2(onRefreshReceived, void(int32_t sequenceId, hal::HWDisplayId display));
+ MOCK_METHOD4(onVsyncReceived,
+ void(int32_t sequenceId, hal::HWDisplayId display, int64_t timestamp,
+ std::optional<hal::VsyncPeriodNanos> vsyncPeriod));
+ MOCK_METHOD3(onVsyncPeriodTimingChangedReceived,
+ void(int32_t sequenceId, hal::HWDisplayId display,
+ const hal::VsyncPeriodChangeTimeline& updatedTimeline));
+ MOCK_METHOD2(onSeamlessPossible, void(int32_t sequenceId, hal::HWDisplayId display));
+};
+
+struct HWComposerTest : public testing::Test {
+ Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+};
+
+struct HWComposerSetConfigurationTest : public HWComposerTest {
+ StrictMock<MockHWC2ComposerCallback> mCallback;
+};
+
+TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) {
+ const std::string kMetadata1Name = "com.example.metadata.1";
+ constexpr bool kMetadata1Mandatory = false;
+ const std::string kMetadata2Name = "com.example.metadata.2";
+ constexpr bool kMetadata2Mandatory = true;
+
+ EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+ EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+ EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+ .WillOnce(DoAll(SetArgPointee<0>(std::vector<hal::LayerGenericMetadataKey>{
+ {kMetadata1Name, kMetadata1Mandatory},
+ {kMetadata2Name, kMetadata2Mandatory},
+ }),
+ Return(hardware::graphics::composer::V2_4::Error::NONE)));
+ EXPECT_CALL(*mHal, registerCallback(_));
+ EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+ impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+ hwc.setConfiguration(&mCallback, 123);
+
+ const auto& supported = hwc.getSupportedLayerGenericMetadata();
+ EXPECT_EQ(2u, supported.size());
+ EXPECT_EQ(1u, supported.count(kMetadata1Name));
+ EXPECT_EQ(kMetadata1Mandatory, supported.find(kMetadata1Name)->second);
+ EXPECT_EQ(1u, supported.count(kMetadata2Name));
+ EXPECT_EQ(kMetadata2Mandatory, supported.find(kMetadata2Name)->second);
+}
+
+TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) {
+ EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+ EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+ EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+ .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+ EXPECT_CALL(*mHal, registerCallback(_));
+ EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+ impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+ hwc.setConfiguration(&mCallback, 123);
+
+ const auto& supported = hwc.getSupportedLayerGenericMetadata();
+ EXPECT_EQ(0u, supported.size());
+}
+
+struct HWComposerLayerTest : public testing::Test {
+ static constexpr hal::HWDisplayId kDisplayId = static_cast<hal::HWDisplayId>(1001);
+ static constexpr hal::HWLayerId kLayerId = static_cast<hal::HWLayerId>(1002);
+
+ HWComposerLayerTest(const std::unordered_set<hal::Capability>& capabilities)
+ : mCapabilies(capabilities) {}
+
+ ~HWComposerLayerTest() override { EXPECT_CALL(*mHal, destroyLayer(kDisplayId, kLayerId)); }
+
+ std::unique_ptr<Hwc2::mock::Composer> mHal{new StrictMock<Hwc2::mock::Composer>()};
+ const std::unordered_set<hal::Capability> mCapabilies;
+ HWC2::impl::Layer mLayer{*mHal, mCapabilies, kDisplayId, kLayerId};
+};
+
+struct HWComposerLayerGenericMetadataTest : public HWComposerLayerTest {
+ static const std::string kLayerGenericMetadata1Name;
+ static constexpr bool kLayerGenericMetadata1Mandatory = false;
+ static const std::vector<uint8_t> kLayerGenericMetadata1Value;
+ static const std::string kLayerGenericMetadata2Name;
+ static constexpr bool kLayerGenericMetadata2Mandatory = true;
+ static const std::vector<uint8_t> kLayerGenericMetadata2Value;
+
+ HWComposerLayerGenericMetadataTest() : HWComposerLayerTest({}) {}
+};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Name =
+ "com.example.metadata.1";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Value = {1u,
+ 2u,
+ 3u};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Name =
+ "com.example.metadata.2";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Value = {45u,
+ 67u};
+
+TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) {
+ EXPECT_CALL(*mHal,
+ setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata1Name,
+ kLayerGenericMetadata1Mandatory,
+ kLayerGenericMetadata1Value))
+ .WillOnce(Return(hardware::graphics::composer::V2_4::Error::NONE));
+ auto result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata1Name,
+ kLayerGenericMetadata1Mandatory,
+ kLayerGenericMetadata1Value);
+ EXPECT_EQ(hal::Error::NONE, result);
+
+ EXPECT_CALL(*mHal,
+ setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata2Name,
+ kLayerGenericMetadata2Mandatory,
+ kLayerGenericMetadata2Value))
+ .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+ result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata2Name,
+ kLayerGenericMetadata2Mandatory,
+ kLayerGenericMetadata2Value);
+ EXPECT_EQ(hal::Error::UNSUPPORTED, result);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 8e7440c..cae317b 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -1,140 +1,271 @@
+/*
+ * Copyright 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
-#define LOG_TAG "LayerHistoryUnittests"
+#define LOG_TAG "LayerHistoryTest"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
-#include <mutex>
-#include <thread>
-
#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfo.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockLayer.h"
using testing::_;
using testing::Return;
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
class LayerHistoryTest : public testing::Test {
-public:
- LayerHistoryTest();
- ~LayerHistoryTest() override;
-
protected:
- std::unique_ptr<LayerHistory> mLayerHistory;
+ static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::PresentTimeHistory::HISTORY_SIZE;
+ static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::MAX_FREQUENT_LAYER_PERIOD_NS;
- static constexpr float MIN_REFRESH_RATE = 30.f;
- static constexpr float MAX_REFRESH_RATE = 90.f;
- static constexpr auto RELEVANT_FRAME_THRESHOLD = 90u;
- static constexpr uint64_t THIRTY_FPS_INTERVAL = 33'333'333;
+ static constexpr float LO_FPS = 30.f;
+ static constexpr nsecs_t LO_FPS_PERIOD = 33'333'333;
- void forceRelevancy(const std::unique_ptr<LayerHistory::LayerHandle>& testLayer) {
- mLayerHistory->setVisibility(testLayer, true);
- for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
- }
- };
+ static constexpr float HI_FPS = 90.f;
+ static constexpr nsecs_t HI_FPS_PERIOD = 11'111'111;
+
+ LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
+
+ impl::LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
+ const impl::LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
+
+ size_t layerCount() const { return mScheduler->layerHistorySize(); }
+ size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+
+ size_t frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+ const auto& infos = history().mLayerInfos;
+ return std::count_if(infos.begin(), infos.begin() + history().mActiveLayersEnd,
+ [now](const auto& pair) { return pair.second->isFrequent(now); });
+ }
+
+ auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
+
+ Hwc2::mock::Display mDisplay;
+ RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0)
+ .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
+ .setConfigGroup(0)
+ .build(),
+ HWC2::Display::Config::Builder(mDisplay, 1)
+ .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
+ .setConfigGroup(0)
+ .build()},
+ HwcConfigIndexType(0)};
+ TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, false)};
+ TestableSurfaceFlinger mFlinger;
+
+ const nsecs_t mTime = systemTime();
};
-LayerHistoryTest::LayerHistoryTest() {
- mLayerHistory = std::make_unique<LayerHistory>();
-}
-LayerHistoryTest::~LayerHistoryTest() {}
-
namespace {
+
TEST_F(LayerHistoryTest, oneLayer) {
- std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer, true);
- for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
- EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ // no layers are returned if no layers are active.
+ ASSERT_TRUE(history().summarize(mTime).empty());
+ EXPECT_EQ(0, activeLayerCount());
+
+ // no layers are returned if active layers have insufficient history.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
+ ASSERT_TRUE(history().summarize(mTime).empty());
+ EXPECT_EQ(1, activeLayerCount());
}
- // Add a few more. This time we should get MAX refresh rate as the layer
- // becomes relevant
- static constexpr auto A_FEW = 10;
- for (auto i = 0u; i < A_FEW; i++) {
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+ // High FPS is returned once enough history has been recorded.
+ for (int i = 0; i < 10; i++) {
+ history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
+ ASSERT_EQ(1, history().summarize(mTime).size());
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
}
}
-TEST_F(LayerHistoryTest, oneHDRLayer) {
- std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer, true);
-
- mLayerHistory->insert(testLayer, 0, true /*isHDR*/);
- EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- EXPECT_EQ(true, mLayerHistory->getDesiredRefreshRateAndHDR().second);
-
- mLayerHistory->setVisibility(testLayer, false);
- EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- EXPECT_EQ(false, mLayerHistory->getDesiredRefreshRateAndHDR().second);
-}
-
TEST_F(LayerHistoryTest, explicitTimestamp) {
- std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
- mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(test30FpsLayer, true);
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
- nsecs_t startTime = systemTime();
- for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = mTime;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += LO_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+ ASSERT_EQ(1, history().summarize(mTime).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(mTime)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
}
TEST_F(LayerHistoryTest, multipleLayers) {
- std::unique_ptr<LayerHistory::LayerHandle> testLayer =
- mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer, true);
- std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
- mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(test30FpsLayer, true);
- std::unique_ptr<LayerHistory::LayerHandle> testLayer2 =
- mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
- mLayerHistory->setVisibility(testLayer2, true);
+ auto layer1 = createLayer();
+ auto layer2 = createLayer();
+ auto layer3 = createLayer();
- nsecs_t startTime = systemTime();
- for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+ EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+ EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+ nsecs_t time = mTime;
+
+ EXPECT_EQ(3, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer1 is active but infrequent.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- startTime = systemTime();
- for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer2 is frequent and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- for (int i = 10; i < RELEVANT_FRAME_THRESHOLD; i++) {
- mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
+ // layer1 is still active but infrequent.
+ history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer1 is no longer active.
+ // layer2 is frequent and has low refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += LO_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- // This frame is only around for 9 occurrences, so it doesn't throw
- // anything off.
- for (int i = 0; i < 9; i++) {
- mLayerHistory->insert(testLayer2, 0, false /*isHDR*/);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 has high refresh rate but not enough history.
+ constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ if (i % RATIO == 0) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ }
+
+ history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
}
- EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
- // After 1200 ms frames become obsolete.
- std::this_thread::sleep_for(std::chrono::milliseconds(1500));
- mLayerHistory->insert(test30FpsLayer,
- startTime + (RELEVANT_FRAME_THRESHOLD * THIRTY_FPS_INTERVAL),
- false /*isHDR*/);
- EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer3 becomes recently active.
+ history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer1 expires.
+ layer1.clear();
+ ASSERT_EQ(2, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_EQ(2, layerCount());
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 becomes inactive.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 expires.
+ layer2.clear();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer3 becomes active and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer3 expires.
+ layer3.clear();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
}
} // namespace
-} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
new file mode 100644
index 0000000..afd2b71
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -0,0 +1,748 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerHistoryTestV2"
+
+#include <Layer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfoV2.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockLayer.h"
+
+using testing::_;
+using testing::Return;
+
+namespace android::scheduler {
+
+class LayerHistoryTestV2 : public testing::Test {
+protected:
+ static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE;
+ static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS;
+ static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE;
+ static constexpr auto PRESENT_TIME_HISTORY_DURATION = LayerInfoV2::HISTORY_DURATION;
+ static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
+ LayerInfoV2::RefreshRateHistory::HISTORY_DURATION;
+
+ static constexpr float LO_FPS = 30.f;
+ static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS);
+
+ static constexpr float HI_FPS = 90.f;
+ static constexpr auto HI_FPS_PERIOD = static_cast<nsecs_t>(1e9f / HI_FPS);
+
+ LayerHistoryTestV2() { mFlinger.resetScheduler(mScheduler); }
+
+ impl::LayerHistoryV2& history() { return *mScheduler->mutableLayerHistoryV2(); }
+ const impl::LayerHistoryV2& history() const { return *mScheduler->mutableLayerHistoryV2(); }
+
+ size_t layerCount() const { return mScheduler->layerHistorySize(); }
+ size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+
+ auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+ const auto& infos = history().mLayerInfos;
+ return std::count_if(infos.begin(),
+ infos.begin() + static_cast<long>(history().mActiveLayersEnd),
+ [now](const auto& pair) { return pair.second->isFrequent(now); });
+ }
+
+ auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+ const auto& infos = history().mLayerInfos;
+ return std::count_if(infos.begin(),
+ infos.begin() + static_cast<long>(history().mActiveLayersEnd),
+ [now](const auto& pair) { return pair.second->isAnimating(now); });
+ }
+
+ void setLayerInfoVote(Layer* layer,
+ LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
+ for (auto& [weak, info] : history().mLayerInfos) {
+ if (auto strong = weak.promote(); strong && strong.get() == layer) {
+ info->setDefaultLayerVote(vote);
+ info->setLayerVote(vote, 0);
+ return;
+ }
+ }
+ }
+
+ auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
+ auto createLayer(std::string name) {
+ return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name)));
+ }
+
+ void recordFramesAndExpect(const sp<mock::MockLayer>& layer, nsecs_t& time, float frameRate,
+ float desiredRefreshRate, int numFrames) {
+ const nsecs_t framePeriod = static_cast<nsecs_t>(1e9f / frameRate);
+ impl::LayerHistoryV2::Summary summary;
+ for (int i = 0; i < numFrames; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += framePeriod;
+
+ summary = history().summarize(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ ASSERT_FLOAT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate)
+ << "Frame rate is " << frameRate;
+ }
+
+ Hwc2::mock::Display mDisplay;
+ RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0)
+ .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
+ .setConfigGroup(0)
+ .build(),
+ HWC2::Display::Config::Builder(mDisplay, 1)
+ .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
+ .setConfigGroup(0)
+ .build()},
+ HwcConfigIndexType(0)};
+ TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)};
+ TestableSurfaceFlinger mFlinger;
+
+};
+
+namespace {
+
+TEST_F(LayerHistoryTestV2, oneLayer) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ const nsecs_t time = systemTime();
+
+ // No layers returned if no layers are active.
+ EXPECT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+
+ // Max returned if active layers have insufficient history.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ }
+
+ // Max is returned since we have enough history but there is no timestamp votes.
+ for (int i = 0; i < 10; i++) {
+ history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ }
+}
+
+TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+
+ history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+ auto summary = history().summarize(time);
+ ASSERT_EQ(1, history().summarize(time).size());
+ // Layer is still considered inactive so we expect to get Min
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
+
+ summary = history().summarize(time);
+ EXPECT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+}
+
+TEST_F(LayerHistoryTestV2, explicitTimestamp) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min);
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max);
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
+ auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree())
+ .WillRepeatedly(
+ Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default)));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive, but the vote stays
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) {
+ auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree())
+ .WillRepeatedly(Return(
+ Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive, but the vote stays
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, multipleLayers) {
+ auto layer1 = createLayer();
+ auto layer2 = createLayer();
+ auto layer3 = createLayer();
+
+ EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(3, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ impl::LayerHistoryV2::Summary summary;
+
+ // layer1 is active but infrequent.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ summary = history().summarize(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer2 is frequent and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ summary = history().summarize(time);
+ }
+
+ // layer1 is still active but infrequent.
+ history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+
+ ASSERT_EQ(2, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
+ ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer1 is no longer active.
+ // layer2 is frequent and has low refresh rate.
+ for (int i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += LO_FPS_PERIOD;
+ summary = history().summarize(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 has high refresh rate but not enough history.
+ constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ if (i % RATIO == 0) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ }
+
+ history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ summary = history().summarize(time);
+ }
+
+ ASSERT_EQ(2, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer3 becomes recently active.
+ history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ summary = history().summarize(time);
+ ASSERT_EQ(2, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, summary[1].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer1 expires.
+ layer1.clear();
+ summary = history().summarize(time);
+ ASSERT_EQ(2, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, summary[1].desiredRefreshRate);
+ EXPECT_EQ(2, layerCount());
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 becomes inactive.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += LO_FPS_PERIOD;
+ summary = history().summarize(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 expires.
+ layer2.clear();
+ summary = history().summarize(time);
+ EXPECT_TRUE(summary.empty());
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer3 becomes active and has high refresh rate.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) {
+ history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+ summary = history().summarize(time);
+ }
+
+ ASSERT_EQ(1, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_FLOAT_EQ(HI_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer3 expires.
+ layer3.clear();
+ summary = history().summarize(time);
+ EXPECT_TRUE(summary.empty());
+ EXPECT_EQ(0, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, inactiveLayers) {
+ auto layer = createLayer();
+
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+
+ // the very first updates makes the layer frequent
+ for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ }
+
+ // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // advance the time for the previous frame to be inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+
+ // Now event if we post a quick few frame we should stay infrequent
+ for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ }
+
+ // More quick frames will get us to frequent again
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += HI_FPS_PERIOD;
+
+ EXPECT_EQ(1, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, invisibleExplicitLayer) {
+ auto explicitVisiblelayer = createLayer();
+ auto explicitInvisiblelayer = createLayer();
+
+ EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree())
+ .WillRepeatedly(Return(
+ Layer::FrameRate(60.0f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+ EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree())
+ .WillRepeatedly(Return(
+ Layer::FrameRate(90.0f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+ nsecs_t time = systemTime();
+
+ // Post a buffer to the layers to make them active
+ history().record(explicitVisiblelayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ history().record(explicitInvisiblelayer.get(), time, time,
+ LayerHistory::LayerUpdateType::Buffer);
+
+ EXPECT_EQ(2, layerCount());
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(60.0f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(2, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, infrequentAnimatingLayer) {
+ auto layer = createLayer();
+
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // layer is active but infrequent.
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // another update with the same cadence keep in infrequent
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // an update as animation will immediately vote for Max
+ history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(1, animatingLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, heuristicLayer60Hz) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+ for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) {
+ recordFramesAndExpect(layer, time, fps, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+ }
+}
+
+TEST_F(LayerHistoryTestV2, heuristicLayer60_30Hz) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+ recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+
+ recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 30.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 30.0f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 60.0f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+}
+
+TEST_F(LayerHistoryTestV2, heuristicLayerNotOscillating) {
+ const auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+ nsecs_t time = systemTime();
+
+ recordFramesAndExpect(layer, time, 27.10f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.90f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.00f, 24.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 26.90f, 24.0f, PRESENT_TIME_HISTORY_SIZE);
+ recordFramesAndExpect(layer, time, 27.10f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+}
+
+class LayerHistoryTestV2Parameterized
+ : public LayerHistoryTestV2,
+ public testing::WithParamInterface<std::chrono::nanoseconds> {};
+
+TEST_P(LayerHistoryTestV2Parameterized, HeuristicLayerWithInfrequentLayer) {
+ std::chrono::nanoseconds infrequentUpdateDelta = GetParam();
+ auto heuristicLayer = createLayer("HeuristicLayer");
+
+ EXPECT_CALL(*heuristicLayer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*heuristicLayer, getFrameRateForLayerTree())
+ .WillRepeatedly(Return(Layer::FrameRate()));
+
+ auto infrequentLayer = createLayer("InfrequentLayer");
+ EXPECT_CALL(*infrequentLayer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*infrequentLayer, getFrameRateForLayerTree())
+ .WillRepeatedly(Return(Layer::FrameRate()));
+
+ const nsecs_t startTime = systemTime();
+
+ const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns;
+ history().record(heuristicLayer.get(), startTime, startTime,
+ LayerHistory::LayerUpdateType::Buffer);
+ history().record(infrequentLayer.get(), startTime, startTime,
+ LayerHistory::LayerUpdateType::Buffer);
+
+ nsecs_t time = startTime;
+ nsecs_t lastInfrequentUpdate = startTime;
+ const int totalInfrequentLayerUpdates = FREQUENT_LAYER_WINDOW_SIZE * 5;
+ int infrequentLayerUpdates = 0;
+ while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) {
+ time += heuristicUpdateDelta.count();
+ history().record(heuristicLayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+
+ if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) {
+ ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates,
+ totalInfrequentLayerUpdates);
+ lastInfrequentUpdate = time;
+ history().record(infrequentLayer.get(), time, time,
+ LayerHistory::LayerUpdateType::Buffer);
+ infrequentLayerUpdates++;
+ }
+
+ if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) {
+ ASSERT_NE(0, history().summarize(time).size());
+ ASSERT_GE(2, history().summarize(time).size());
+
+ bool max = false;
+ bool min = false;
+ float heuristic = 0;
+ for (const auto& layer : history().summarize(time)) {
+ if (layer.vote == LayerHistory::LayerVoteType::Heuristic) {
+ heuristic = layer.desiredRefreshRate;
+ } else if (layer.vote == LayerHistory::LayerVoteType::Max) {
+ max = true;
+ } else if (layer.vote == LayerHistory::LayerVoteType::Min) {
+ min = true;
+ }
+ }
+
+ if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) {
+ EXPECT_FLOAT_EQ(24.0f, heuristic);
+ EXPECT_FALSE(max);
+ if (history().summarize(time).size() == 2) {
+ EXPECT_TRUE(min);
+ }
+ }
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestV2Parameterized,
+ ::testing::Values(1s, 2s, 3s, 4s, 5s));
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
similarity index 75%
rename from services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
rename to services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index eff22b6..0208728 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -21,17 +21,17 @@
#include <utils/Log.h>
#include "AsyncCallRecorder.h"
-#include "Scheduler/IdleTimer.h"
+#include "Scheduler/OneShotTimer.h"
using namespace std::chrono_literals;
namespace android {
namespace scheduler {
-class IdleTimerTest : public testing::Test {
+class OneShotTimerTest : public testing::Test {
protected:
- IdleTimerTest() = default;
- ~IdleTimerTest() override = default;
+ OneShotTimerTest() = default;
+ ~OneShotTimerTest() override = default;
// This timeout should be used when a 3ms callback is expected.
// While the tests typically request a callback after 3ms, the scheduler
@@ -46,7 +46,7 @@
AsyncCallRecorder<void (*)()> mResetTimerCallback;
AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
- std::unique_ptr<IdleTimer> mIdleTimer;
+ std::unique_ptr<OneShotTimer> mIdleTimer;
void clearPendingCallbacks() {
while (mExpiredTimerCallback.waitForCall(0us).has_value()) {
@@ -55,13 +55,14 @@
};
namespace {
-TEST_F(IdleTimerTest, createAndDestroyTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {});
+TEST_F(OneShotTimerTest, createAndDestroyTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
+ 3ms, [] {}, [] {});
}
-TEST_F(IdleTimerTest, startStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startStopTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
auto startTime = std::chrono::steady_clock::now();
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -70,7 +71,7 @@
bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value();
// Under ideal conditions there should be no event. But occasionally
// it is possible that the wait just prior takes more than 30ms, and
- // a callback is observed. We check the elapsed time since before the IdleTimer
+ // a callback is observed. We check the elapsed time since before the OneShotTimer
// thread was started as a sanity check to not have a flakey test.
EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
@@ -79,9 +80,9 @@
mIdleTimer->stop();
}
-TEST_F(IdleTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
// Observe any event that happens in about 25ms. We don't care if one was
@@ -104,9 +105,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, resetBackToBackTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetBackToBackTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -135,9 +136,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, startNotCalledTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startNotCalledTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
// The start hasn't happened, so the callback does not happen.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
@@ -147,9 +148,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, idleTimerIdlesTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -167,18 +168,18 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
}
-TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
@@ -190,9 +191,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
}
-TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
new file mode 100644
index 0000000..0b74682
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <log/log.h>
+#include <thread>
+
+#include "Scheduler/PhaseOffsets.h"
+
+using namespace testing;
+
+namespace android {
+namespace scheduler {
+
+class TestablePhaseOffsetsAsDurations : public impl::PhaseDurations {
+public:
+ TestablePhaseOffsetsAsDurations(float currentFps, nsecs_t sfDuration, nsecs_t appDuration,
+ nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
+ nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration)
+ : impl::PhaseDurations({60.0f, 90.0f}, currentFps, sfDuration, appDuration,
+ sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration,
+ appEarlyGlDuration) {}
+};
+
+class PhaseDurationTest : public testing::Test {
+protected:
+ PhaseDurationTest()
+ : mPhaseDurations(60.0f, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
+ 21'000'000) {}
+
+ ~PhaseDurationTest() = default;
+
+ TestablePhaseOffsetsAsDurations mPhaseDurations;
+};
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_60Hz) {
+ mPhaseDurations.setRefreshRateFps(60.0f);
+ auto currentOffsets = mPhaseDurations.getCurrentOffsets();
+ auto offsets = mPhaseDurations.getOffsetsForRefreshRate(60.0f);
+
+ EXPECT_EQ(currentOffsets, offsets);
+ EXPECT_EQ(offsets.late.sf, 6'166'667);
+
+ EXPECT_EQ(offsets.late.app, 2'333'334);
+
+ EXPECT_EQ(offsets.early.sf, 666'667);
+
+ EXPECT_EQ(offsets.early.app, 833'334);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 3'166'667);
+
+ EXPECT_EQ(offsets.earlyGl.app, 15'500'001);
+}
+
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) {
+ mPhaseDurations.setRefreshRateFps(90.0f);
+ auto currentOffsets = mPhaseDurations.getCurrentOffsets();
+ auto offsets = mPhaseDurations.getOffsetsForRefreshRate(90.0f);
+
+ EXPECT_EQ(currentOffsets, offsets);
+ EXPECT_EQ(offsets.late.sf, 611'111);
+
+ EXPECT_EQ(offsets.late.app, 2'333'333);
+
+ EXPECT_EQ(offsets.early.sf, -4'888'889);
+
+ EXPECT_EQ(offsets.early.app, 833'333);
+
+ EXPECT_EQ(offsets.earlyGl.sf, -2'388'889);
+
+ EXPECT_EQ(offsets.earlyGl.app, 9'944'444);
+}
+
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) {
+ TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);
+
+ auto validateOffsets = [](auto& offsets) {
+ EXPECT_EQ(offsets.late.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.late.app, 1'000'000);
+
+ EXPECT_EQ(offsets.early.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.early.app, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+ };
+
+ phaseOffsetsWithDefaultValues.setRefreshRateFps(90.0f);
+ auto currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
+ auto offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
+ EXPECT_EQ(currentOffsets, offsets);
+ validateOffsets(offsets);
+
+ phaseOffsetsWithDefaultValues.setRefreshRateFps(60.0f);
+ currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
+ offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
+ EXPECT_EQ(currentOffsets, offsets);
+ validateOffsets(offsets);
+}
+
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_unknownRefreshRate) {
+ auto offsets = mPhaseDurations.getOffsetsForRefreshRate(14.7f);
+
+ EXPECT_EQ(offsets.late.sf, 57'527'208);
+
+ EXPECT_EQ(offsets.late.app, 37'027'208);
+
+ EXPECT_EQ(offsets.early.sf, 52'027'208);
+
+ EXPECT_EQ(offsets.early.app, 35'527'208);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 54'527'208);
+
+ EXPECT_EQ(offsets.earlyGl.app, 33'527'208);
+}
+
+} // namespace
+
+class TestablePhaseOffsets : public impl::PhaseOffsets {
+public:
+ TestablePhaseOffsets()
+ : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 1'000'000, 1'000'000, {}, {}, {}, {},
+ 10'000'000) {}
+};
+
+class PhaseOffsetsTest : public testing::Test {
+protected:
+ PhaseOffsetsTest() = default;
+ ~PhaseOffsetsTest() = default;
+
+ TestablePhaseOffsets mPhaseOffsets;
+};
+
+namespace {
+TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) {
+ auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(14.7f);
+
+ EXPECT_EQ(offsets.late.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.late.app, 1'000'000);
+
+ EXPECT_EQ(offsets.early.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.early.app, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+
+ EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+}
+
+} // namespace
+} // namespace scheduler
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/PromiseTest.cpp b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
new file mode 100644
index 0000000..e4dc1fe
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 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 <algorithm>
+#include <future>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "Promise.h"
+
+namespace android {
+namespace {
+
+using Bytes = std::vector<uint8_t>;
+
+Bytes decrement(Bytes bytes) {
+ std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; });
+ return bytes;
+}
+
+} // namespace
+
+TEST(PromiseTest, yield) {
+ EXPECT_EQ(42, promise::yield(42).get());
+
+ auto ptr = std::make_unique<char>('!');
+ auto future = promise::yield(std::move(ptr));
+ EXPECT_EQ('!', *future.get());
+}
+
+TEST(PromiseTest, chain) {
+ std::packaged_task<const char*()> fetchString([] { return "ifmmp-"; });
+
+ std::packaged_task<Bytes(std::string)> appendString([](std::string str) {
+ str += "!xpsme";
+ return Bytes{str.begin(), str.end()};
+ });
+
+ std::packaged_task<std::future<Bytes>(Bytes)> decrementBytes(
+ [](Bytes bytes) { return promise::defer(decrement, std::move(bytes)); });
+
+ auto fetch = fetchString.get_future();
+ std::thread fetchThread(std::move(fetchString));
+
+ std::thread appendThread, decrementThread;
+
+ EXPECT_EQ("hello, world",
+ promise::chain(std::move(fetch))
+ .then([](const char* str) { return std::string(str); })
+ .then([&](std::string str) {
+ auto append = appendString.get_future();
+ appendThread = std::thread(std::move(appendString), std::move(str));
+ return append;
+ })
+ .then([&](Bytes bytes) {
+ auto decrement = decrementBytes.get_future();
+ decrementThread = std::thread(std::move(decrementBytes),
+ std::move(bytes));
+ return decrement;
+ })
+ .then([](std::future<Bytes> bytes) { return bytes; })
+ .then([](const Bytes& bytes) {
+ return std::string(bytes.begin(), bytes.end());
+ })
+ .get());
+
+ fetchThread.join();
+ appendThread.join();
+ decrementThread.join();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index f315a8a..1f6f166 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -21,8 +21,10 @@
#include <log/log.h>
#include <thread>
+#include "../../Scheduler/RefreshRateConfigs.h"
#include "DisplayHardware/HWC2.h"
#include "Scheduler/RefreshRateConfigs.h"
+#include "mock/DisplayHardware/MockDisplay.h"
using namespace std::chrono_literals;
using testing::_;
@@ -30,29 +32,111 @@
namespace android {
namespace scheduler {
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+namespace hal = android::hardware::graphics::composer::hal;
+
using RefreshRate = RefreshRateConfigs::RefreshRate;
+using LayerVoteType = RefreshRateConfigs::LayerVoteType;
+using LayerRequirement = RefreshRateConfigs::LayerRequirement;
class RefreshRateConfigsTest : public testing::Test {
protected:
- static constexpr int CONFIG_ID_60 = 0;
- static constexpr hwc2_config_t HWC2_CONFIG_ID_60 = 0;
- static constexpr int CONFIG_ID_90 = 1;
- static constexpr hwc2_config_t HWC2_CONFIG_ID_90 = 1;
- static constexpr int64_t VSYNC_60 = 16666667;
- static constexpr int64_t VSYNC_90 = 11111111;
-
RefreshRateConfigsTest();
~RefreshRateConfigsTest();
- void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) {
- ASSERT_EQ(left.configId, right.configId);
- ASSERT_EQ(left.name, right.name);
- ASSERT_EQ(left.fps, right.fps);
- ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod);
+ float findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, float frameRate) {
+ return refreshRateConfigs.findClosestKnownFrameRate(frameRate);
}
+
+ std::vector<float> getKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs) {
+ return refreshRateConfigs.mKnownFrameRates;
+ }
+
+ // Test config IDs
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_60 = HwcConfigIndexType(0);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(1);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_72 = HwcConfigIndexType(2);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_120 = HwcConfigIndexType(3);
+ static inline const HwcConfigIndexType HWC_CONFIG_ID_30 = HwcConfigIndexType(4);
+
+ // Test configs
+ std::shared_ptr<const HWC2::Display::Config> mConfig60 =
+ createConfig(HWC_CONFIG_ID_60, 0, static_cast<int64_t>(1e9f / 60));
+ std::shared_ptr<const HWC2::Display::Config> mConfig90 =
+ createConfig(HWC_CONFIG_ID_90, 0, static_cast<int64_t>(1e9f / 90));
+ std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentGroup =
+ createConfig(HWC_CONFIG_ID_90, 1, static_cast<int64_t>(1e9f / 90));
+ std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentResolution =
+ createConfig(HWC_CONFIG_ID_90, 0, static_cast<int64_t>(1e9f / 90), 111, 222);
+ std::shared_ptr<const HWC2::Display::Config> mConfig72 =
+ createConfig(HWC_CONFIG_ID_72, 0, static_cast<int64_t>(1e9f / 72));
+ std::shared_ptr<const HWC2::Display::Config> mConfig72DifferentGroup =
+ createConfig(HWC_CONFIG_ID_72, 1, static_cast<int64_t>(1e9f / 72));
+ std::shared_ptr<const HWC2::Display::Config> mConfig120 =
+ createConfig(HWC_CONFIG_ID_120, 0, static_cast<int64_t>(1e9f / 120));
+ std::shared_ptr<const HWC2::Display::Config> mConfig120DifferentGroup =
+ createConfig(HWC_CONFIG_ID_120, 1, static_cast<int64_t>(1e9f / 120));
+ std::shared_ptr<const HWC2::Display::Config> mConfig30 =
+ createConfig(HWC_CONFIG_ID_30, 0, static_cast<int64_t>(1e9f / 30));
+
+ // Test device configurations
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m60OnlyConfigDevice = {mConfig60};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90Device = {mConfig60, mConfig90};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90DeviceWithDifferentGroups =
+ {mConfig60, mConfig90DifferentGroup};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90DeviceWithDifferentResolutions =
+ {mConfig60, mConfig90DifferentResolution};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_72_90Device = {mConfig60,
+ mConfig90,
+ mConfig72};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90_72_120Device = {mConfig60,
+ mConfig90,
+ mConfig72,
+ mConfig120};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_72_90_120Device = {mConfig60,
+ mConfig90,
+ mConfig72,
+ mConfig120,
+ mConfig30};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60Device =
+ {mConfig60, mConfig90DifferentGroup, mConfig72DifferentGroup, mConfig120DifferentGroup,
+ mConfig30};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_72_90Device =
+ {mConfig60, mConfig90, mConfig72, mConfig120DifferentGroup, mConfig30};
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_90Device =
+ {mConfig60, mConfig90, mConfig72DifferentGroup, mConfig120DifferentGroup, mConfig30};
+
+ // Expected RefreshRate objects
+ RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, "60fps", 60,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpectedAlmost60Config = {HWC_CONFIG_ID_60,
+ createConfig(HWC_CONFIG_ID_60, 0, 16666665), "60fps", 60,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, "90fps", 90,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90DifferentGroupConfig = {HWC_CONFIG_ID_90, mConfig90DifferentGroup,
+ "90fps", 90, RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected90DifferentResolutionConfig = {HWC_CONFIG_ID_90,
+ mConfig90DifferentResolution, "90fps", 90,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected72Config = {HWC_CONFIG_ID_72, mConfig72, "72fps", 72,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected30Config = {HWC_CONFIG_ID_30, mConfig30, "30fps", 30,
+ RefreshRate::ConstructorTag(0)};
+ RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, "120fps", 120,
+ RefreshRate::ConstructorTag(0)};
+
+ Hwc2::mock::Display mDisplay;
+
+private:
+ std::shared_ptr<const HWC2::Display::Config> createConfig(HwcConfigIndexType configId,
+ int32_t configGroup,
+ int64_t vsyncPeriod,
+ int32_t hight = -1,
+ int32_t width = -1);
};
+using Builder = HWC2::Display::Config::Builder;
+
RefreshRateConfigsTest::RefreshRateConfigsTest() {
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
@@ -65,44 +149,1328 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
+std::shared_ptr<const HWC2::Display::Config> RefreshRateConfigsTest::createConfig(
+ HwcConfigIndexType configId, int32_t configGroup, int64_t vsyncPeriod, int32_t hight,
+ int32_t width) {
+ return HWC2::Display::Config::Builder(mDisplay, hal::HWConfigId(configId.value()))
+ .setVsyncPeriod(int32_t(vsyncPeriod))
+ .setConfigGroup(configGroup)
+ .setHeight(hight)
+ .setWidth(width)
+ .build();
+}
+
namespace {
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) {
- std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}};
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) {
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfig=*/0);
- ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+}
+
+TEST_F(RefreshRateConfigsTest, invalidPolicy) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0);
+ ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0);
}
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
- std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60},
- {HWC2_CONFIG_ID_90, VSYNC_90}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfig=*/0);
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
- const auto& rates = refreshRateConfigs->getRefreshRateMap();
- ASSERT_EQ(2, rates.size());
- const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
- const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE);
- ASSERT_NE(rates.end(), defaultRate);
- ASSERT_NE(rates.end(), performanceRate);
+ const auto& minRate = refreshRateConfigs->getMinRefreshRate();
+ const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
- RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60};
- assertRatesEqual(expectedDefaultConfig, defaultRate->second);
- RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90,
- HWC2_CONFIG_ID_90};
- assertRatesEqual(expectedPerformanceConfig, performanceRate->second);
+ ASSERT_EQ(mExpected60Config, minRate);
+ ASSERT_EQ(mExpected90Config, performanceRate);
- assertRatesEqual(expectedDefaultConfig,
- refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT));
- assertRatesEqual(expectedPerformanceConfig,
- refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE));
+ const auto& minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy();
+ const auto& performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy();
+ ASSERT_EQ(minRateByPolicy, minRate);
+ ASSERT_EQ(performanceRateByPolicy, performanceRate);
}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differentGroups) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+ const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
+ const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+ const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+ ASSERT_EQ(mExpected60Config, minRate);
+ ASSERT_EQ(mExpected60Config, minRate60);
+ ASSERT_EQ(mExpected60Config, performanceRate60);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+
+ const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+ const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+ ASSERT_EQ(mExpected90DifferentGroupConfig, performanceRate);
+ ASSERT_EQ(mExpected90DifferentGroupConfig, minRate90);
+ ASSERT_EQ(mExpected90DifferentGroupConfig, performanceRate90);
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differentResolutions) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentResolutions,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+ const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
+ const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+ const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+ ASSERT_EQ(mExpected60Config, minRate);
+ ASSERT_EQ(mExpected60Config, minRate60);
+ ASSERT_EQ(mExpected60Config, performanceRate60);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+
+ const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+ const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+ ASSERT_EQ(mExpected90DifferentResolutionConfig, performanceRate);
+ ASSERT_EQ(mExpected90DifferentResolutionConfig, minRate90);
+ ASSERT_EQ(mExpected90DifferentResolutionConfig, performanceRate90);
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+ auto& performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+ ASSERT_EQ(mExpected60Config, minRate);
+ ASSERT_EQ(mExpected90Config, performanceRate);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+
+ auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+ auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+ ASSERT_EQ(mExpected60Config, minRate60);
+ ASSERT_EQ(mExpected60Config, performanceRate60);
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+ {
+ auto& current = refreshRateConfigs->getCurrentRefreshRate();
+ EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_60);
+ }
+
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+ {
+ auto& current = refreshRateConfigs->getCurrentRefreshRate();
+ EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
+ }
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+ {
+ auto& current = refreshRateConfigs->getCurrentRefreshRate();
+ EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ const auto makeLayerRequirements = [](float refreshRate) -> std::vector<LayerRequirement> {
+ return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f,
+ /*focused*/ false}};
+ };
+
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_72_90Device, /*currentConfigId=*/
+ HWC_CONFIG_ID_72);
+
+ // If there are no layers we select the default frame rate, which is the max of the primary
+ // range.
+ auto layers = std::vector<LayerRequirement>{};
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ lr.name = "Min";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ lr.name = "Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ lr.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 45.0f;
+ lr.name = "45Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 30.0f;
+ lr.name = "30Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ lr.name = "24Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.name = "";
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_72_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 48.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 48.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "60Hz ExplicitDefault";
+ EXPECT_EQ(mExpected120Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.name = "24Hz Heuristic";
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.name = "24Hz ExplicitExactOrMultiple";
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.name = "24Hz ExplicitDefault";
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.name = "90Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ EXPECT_EQ(mExpected30Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 30.0f;
+ EXPECT_EQ(mExpected30Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_72_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::Min;
+ lr.name = "Min";
+ EXPECT_EQ(mExpected30Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ lr.name = "Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 90.0f;
+ lr.vote = LayerVoteType::Heuristic;
+ lr.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Heuristic";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ lr.desiredRefreshRate = 45.0f;
+ lr.name = "45Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ lr.desiredRefreshRate = 30.0f;
+ lr.name = "30Hz Heuristic";
+ EXPECT_EQ(mExpected30Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ lr.name = "24Hz Heuristic";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ lr.desiredRefreshRate = 24.0f;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.name = "24Hz ExplicitExactOrMultiple";
+ EXPECT_EQ(mExpected72Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::Min;
+ lr2.vote = LayerVoteType::Max;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::Min;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::Min;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 24.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::Max;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::Max;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 15.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 30.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 45.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
+ lr.desiredRefreshRate = fps;
+ const auto& refreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+ EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent_Explicit) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(mExpected90Config, refreshRateConfigs->getRefreshRateForContent(layers));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getBestRefreshRate_Explicit) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::Heuristic;
+ lr1.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, testInPolicy) {
+ ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(60.000004f, 60.000004f));
+ ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(59.0f, 60.1f));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(75.0f, 90.0f));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(60.0011f, 90.0f));
+ ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50.0f, 59.998f));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
+ lr.desiredRefreshRate = fps;
+ const auto& refreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+ EXPECT_EQ(mExpected90Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.name = "90Hz ExplicitDefault";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 30.0f;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 30.0f;
+ lr1.name = "30Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::NoVote;
+ lr2.name = "NoVote";
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::NoVote;
+ lr2.name = "NoVote";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Max;
+ lr2.name = "Max";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ // The other layer starts to provide buffers
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.name = "90Hz Heuristic";
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, touchConsidered) {
+ RefreshRateConfigs::GlobalSignals consideredSignals;
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false}, &consideredSignals);
+ EXPECT_EQ(false, consideredSignals.touch);
+
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = false}, &consideredSignals);
+ EXPECT_EQ(true, consideredSignals.touch);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+ &consideredSignals);
+ EXPECT_EQ(true, consideredSignals.touch);
+
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+ &consideredSignals);
+ EXPECT_EQ(false, consideredSignals.touch);
+
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+ &consideredSignals);
+ EXPECT_EQ(true, consideredSignals.touch);
+
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr1.desiredRefreshRate = 60.0f;
+ lr1.name = "60Hz ExplicitExactOrMultiple";
+ lr2.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.name = "60Hz Heuristic";
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+ &consideredSignals);
+ EXPECT_EQ(false, consideredSignals.touch);
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90_72_120Device, /*currentConfigId=*/
+ HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ // Prepare a table with the vote and the expected refresh rate
+ const std::vector<std::pair<float, float>> testCases = {
+ {130, 120}, {120, 120}, {119, 120}, {110, 120},
+
+ {100, 90}, {90, 90}, {89, 90},
+
+ {80, 72}, {73, 72}, {72, 72}, {71, 72}, {70, 72},
+
+ {65, 60}, {60, 60}, {59, 60}, {58, 60},
+
+ {55, 90}, {50, 90}, {45, 90},
+
+ {42, 120}, {40, 120}, {39, 120},
+
+ {37, 72}, {36, 72}, {35, 72},
+
+ {30, 60},
+ };
+
+ for (const auto& test : testCases) {
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = test.first;
+
+ std::stringstream ss;
+ ss << "ExplicitDefault " << test.first << " fps";
+ lr.name = ss.str();
+
+ const auto& refreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+ EXPECT_FLOAT_EQ(refreshRate.getFps(), test.second)
+ << "Expecting " << test.first << "fps => " << test.second << "Hz";
+ }
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+ 0);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ RefreshRateConfigs::GlobalSignals consideredSignals;
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz ExplicitDefault";
+ lr.focused = true;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = true},
+ &consideredSignals));
+ EXPECT_EQ(false, consideredSignals.touch);
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+ 0);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = 90.0f;
+ lr.name = "90Hz ExplicitDefault";
+ lr.focused = true;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true}));
+}
+
+TEST_F(RefreshRateConfigsTest,
+ getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+ 0);
+
+ RefreshRateConfigs::GlobalSignals consideredSignals;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false},
+ &consideredSignals));
+ EXPECT_EQ(false, consideredSignals.touch);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz ExplicitExactOrMultiple";
+ lr.focused = false;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.focused = true;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::ExplicitDefault;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz ExplicitDefault";
+ lr.focused = false;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.focused = true;
+ EXPECT_EQ(mExpected60Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Heuristic;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Heuristic";
+ lr.focused = false;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.focused = true;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Max;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Max";
+ lr.focused = false;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.focused = true;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.vote = LayerVoteType::Min;
+ lr.desiredRefreshRate = 60.0f;
+ lr.name = "60Hz Min";
+ lr.focused = false;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+ lr.focused = true;
+ EXPECT_EQ(mExpected90Config,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, groupSwitching) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& layer = layers[0];
+ layer.vote = LayerVoteType::ExplicitDefault;
+ layer.desiredRefreshRate = 90.0f;
+ layer.name = "90Hz ExplicitDefault";
+
+ ASSERT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+
+ RefreshRateConfigs::Policy policy;
+ policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+ policy.allowGroupSwitching = true;
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
+ ASSERT_EQ(HWC_CONFIG_ID_90,
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+ .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m30_60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ layers[0].name = "Test layer";
+
+ // Return the config ID from calling getBestRefreshRate() for a single layer with the
+ // given voteType and fps.
+ auto getFrameRate = [&](LayerVoteType voteType, float fps, bool touchActive = false,
+ bool focused = true) -> HwcConfigIndexType {
+ layers[0].vote = voteType;
+ layers[0].desiredRefreshRate = fps;
+ layers[0].focused = focused;
+ return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false})
+ .getConfigId();
+ };
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {30.f, 60.f}, {30.f, 90.f}}),
+ 0);
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false})
+ .getConfigId());
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+
+ // Layers not focused are not allowed to override primary config
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/false,
+ /*focused=*/false));
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/false,
+ /*focused=*/false));
+
+ // Touch boost should be restricted to the primary range.
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
+ // When we're higher than the primary range max due to a layer frame rate setting, touch boost
+ // shouldn't drag us back down to the primary range max.
+ EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true));
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}),
+ 0);
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+}
+
+TEST_F(RefreshRateConfigsTest, idle) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ layers[0].name = "Test layer";
+
+ const auto getIdleFrameRate = [&](LayerVoteType voteType,
+ bool touchActive) -> HwcConfigIndexType {
+ layers[0].vote = voteType;
+ layers[0].desiredRefreshRate = 90.f;
+ RefreshRateConfigs::GlobalSignals consideredSignals;
+ const auto configId =
+ refreshRateConfigs
+ ->getBestRefreshRate(layers, {.touch = touchActive, .idle = true},
+ &consideredSignals)
+ .getConfigId();
+ // Refresh rate will be chosen by either touch state or idle state
+ EXPECT_EQ(!touchActive, consideredSignals.idle);
+ return configId;
+ };
+
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+ {HWC_CONFIG_ID_60, {60.f, 90.f}, {60.f, 90.f}}),
+ 0);
+
+ // Idle should be lower priority than touch boost.
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::NoVote, /*touchActive=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Min, /*touchActive=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Max, /*touchActive=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Heuristic, /*touchActive=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ getIdleFrameRate(LayerVoteType::ExplicitDefault, /*touchActive=*/true));
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, /*touchActive=*/true));
+
+ // With no layers, idle should still be lower priority than touch boost.
+ EXPECT_EQ(HWC_CONFIG_ID_90,
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true})
+ .getConfigId());
+
+ // Idle should be higher precedence than other layer frame rate considerations.
+ refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::NoVote, /*touchActive=*/false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Min, /*touchActive=*/false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Max, /*touchActive=*/false));
+ EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Heuristic, /*touchActive=*/false));
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ getIdleFrameRate(LayerVoteType::ExplicitDefault, /*touchActive=*/false));
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, /*touchActive=*/false));
+
+ // Idle should be applied rather than the current config when there are no layers.
+ EXPECT_EQ(HWC_CONFIG_ID_60,
+ refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = true})
+ .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) {
+ const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, fps);
+ float expectedFrameRate;
+ if (fps < 26.91f) {
+ expectedFrameRate = 24.0f;
+ } else if (fps < 37.51f) {
+ expectedFrameRate = 30.0f;
+ } else if (fps < 52.51f) {
+ expectedFrameRate = 45.0f;
+ } else if (fps < 66.01f) {
+ expectedFrameRate = 60.0f;
+ } else if (fps < 81.01f) {
+ expectedFrameRate = 72.0f;
+ } else {
+ expectedFrameRate = 90.0f;
+ }
+ EXPECT_FLOAT_EQ(expectedFrameRate, knownFrameRate)
+ << "findClosestKnownFrameRate(" << fps << ") = " << knownFrameRate;
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) {
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ struct ExpectedRate {
+ float rate;
+ const RefreshRate& expected;
+ };
+
+ /* clang-format off */
+ std::vector<ExpectedRate> knownFrameRatesExpectations = {
+ {24.0f, mExpected60Config},
+ {30.0f, mExpected60Config},
+ {45.0f, mExpected90Config},
+ {60.0f, mExpected60Config},
+ {72.0f, mExpected90Config},
+ {90.0f, mExpected90Config},
+ };
+ /* clang-format on */
+
+ // Make sure the test tests all the known frame rate
+ const auto knownFrameRateList = getKnownFrameRate(*refreshRateConfigs);
+ const auto equal = std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
+ knownFrameRatesExpectations.begin(),
+ [](float a, const ExpectedRate& b) { return a == b.rate; });
+ EXPECT_TRUE(equal);
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& layer = layers[0];
+ layer.vote = LayerVoteType::Heuristic;
+ for (const auto& expectedRate : knownFrameRatesExpectations) {
+ layer.desiredRefreshRate = expectedRate.rate;
+ const auto& refreshRate =
+ refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+ EXPECT_EQ(expectedRate.expected, refreshRate);
+ }
+}
+
+TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
+ EXPECT_TRUE(mExpected60Config < mExpected90Config);
+ EXPECT_FALSE(mExpected60Config < mExpected60Config);
+ EXPECT_FALSE(mExpected90Config < mExpected90Config);
+}
+
+TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
+ using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
+
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(m60_90Device,
+ /*currentConfigId=*/HWC_CONFIG_ID_90);
+ // SetPolicy(60, 90), current 90Hz => TurnOn.
+ EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+ // SetPolicy(60, 90), current 60Hz => TurnOn.
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 90}}), 0);
+ EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+ // SetPolicy(60, 60), current 60Hz => NoChange, avoid extra calls.
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+ EXPECT_EQ(KernelIdleTimerAction::NoChange, refreshRateConfigs->getIdleTimerAction());
+
+ // SetPolicy(90, 90), current 90Hz => TurnOff.
+ ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+ EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
new file mode 100644
index 0000000..43b8e01
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2020 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "EffectLayer.h"
+#include "Layer.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+
+namespace android {
+
+using testing::_;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+/**
+ * This class covers all the test that are related to refresh rate selection.
+ */
+class RefreshRateSelectionTest : public testing::Test {
+public:
+ RefreshRateSelectionTest();
+ ~RefreshRateSelectionTest() override;
+
+protected:
+ static constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+ static constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+ static constexpr uint32_t WIDTH = 100;
+ static constexpr uint32_t HEIGHT = 100;
+ static constexpr uint32_t LAYER_FLAGS = 0;
+ static constexpr int32_t PRIORITY_UNSET = -1;
+
+ void setupScheduler();
+ void setupComposer(int virtualDisplayCount);
+ sp<BufferQueueLayer> createBufferQueueLayer();
+ sp<BufferStateLayer> createBufferStateLayer();
+ sp<EffectLayer> createEffectLayer();
+
+ void setParent(Layer* child, Layer* parent);
+ void commitTransaction(Layer* layer);
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+
+ sp<Client> mClient;
+ sp<Layer> mParent;
+ sp<Layer> mChild;
+ sp<Layer> mGrandChild;
+};
+
+RefreshRateSelectionTest::RefreshRateSelectionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ setupScheduler();
+ setupComposer(0);
+}
+
+RefreshRateSelectionTest::~RefreshRateSelectionTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+sp<BufferQueueLayer> RefreshRateSelectionTest::createBufferQueueLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferQueueLayer(args);
+}
+
+sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferStateLayer(args);
+}
+
+sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
+ sp<Client> client;
+ LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+ LayerMetadata());
+ return new EffectLayer(args);
+}
+
+void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
+ child->setParent(parent);
+}
+
+void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
+ layer->commitTransaction(layer->getCurrentState());
+}
+
+void RefreshRateSelectionTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+ EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*primaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(primaryDispSync),
+ std::make_unique<mock::EventControlThread>(), std::move(eventThread),
+ std::move(sfEventThread));
+}
+
+void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferQueueLayers) {
+ mParent = createBufferQueueLayer();
+ mChild = createBufferQueueLayer();
+ setParent(mChild.get(), mParent.get());
+ mGrandChild = createBufferQueueLayer();
+ setParent(mGrandChild.get(), mChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child has its own priority.
+ mGrandChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child inherits from his parent.
+ mChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Grandchild inherits from his grand parent.
+ mParent->setFrameRateSelectionPriority(1);
+ commitTransaction(mParent.get());
+ mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) {
+ mParent = createBufferStateLayer();
+ mChild = createBufferStateLayer();
+ setParent(mChild.get(), mParent.get());
+ mGrandChild = createBufferStateLayer();
+ setParent(mGrandChild.get(), mChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child has its own priority.
+ mGrandChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child inherits from his parent.
+ mChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Grandchild inherits from his grand parent.
+ mParent->setFrameRateSelectionPriority(1);
+ commitTransaction(mParent.get());
+ mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) {
+ mParent = createEffectLayer();
+ mChild = createEffectLayer();
+ setParent(mChild.get(), mParent.get());
+ mGrandChild = createEffectLayer();
+ setParent(mGrandChild.get(), mChild.get());
+
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child has its own priority.
+ mGrandChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Child inherits from his parent.
+ mChild->setFrameRateSelectionPriority(1);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+ // Grandchild inherits from his grand parent.
+ mParent->setFrameRateSelectionPriority(1);
+ commitTransaction(mParent.get());
+ mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mChild.get());
+ mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+ commitTransaction(mGrandChild.get());
+ ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+ ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+} // namespace
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index cec0b32..de66f8f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -22,9 +26,11 @@
#include <thread>
#include "Scheduler/RefreshRateStats.h"
+#include "mock/DisplayHardware/MockDisplay.h"
#include "mock/MockTimeStats.h"
using namespace std::chrono_literals;
+using android::hardware::graphics::composer::hal::PowerMode;
using testing::_;
using testing::AtLeast;
@@ -33,26 +39,31 @@
class RefreshRateStatsTest : public testing::Test {
protected:
- static constexpr int CONFIG_ID_90 = 0;
- static constexpr int CONFIG_ID_60 = 1;
+ static inline const auto CONFIG_ID_0 = HwcConfigIndexType(0);
+ static inline const auto CONFIG_ID_1 = HwcConfigIndexType(1);
+ static inline const auto CONFIG_GROUP_0 = 0;
static constexpr int64_t VSYNC_90 = 11111111;
static constexpr int64_t VSYNC_60 = 16666667;
RefreshRateStatsTest();
~RefreshRateStatsTest();
- void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) {
- mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>(
- /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0);
- mRefreshRateStats =
- std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
- /*currentConfig=*/0,
- /*currentPowerMode=*/HWC_POWER_MODE_OFF);
+ void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+ mRefreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
+ mRefreshRateStats = std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
+ /*currentConfigId=*/CONFIG_ID_0,
+ /*currentPowerMode=*/PowerMode::OFF);
}
+ Hwc2::mock::Display mDisplay;
mock::TimeStats mTimeStats;
std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
std::unique_ptr<RefreshRateStats> mRefreshRateStats;
+
+ std::shared_ptr<const HWC2::Display::Config> createConfig(HwcConfigIndexType configId,
+ int32_t configGroup,
+ int64_t vsyncPeriod);
};
RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -67,12 +78,20 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
+std::shared_ptr<const HWC2::Display::Config> RefreshRateStatsTest::createConfig(
+ HwcConfigIndexType configId, int32_t configGroup, int64_t vsyncPeriod) {
+ return HWC2::Display::Config::Builder(mDisplay, configId.value())
+ .setVsyncPeriod(int32_t(vsyncPeriod))
+ .setConfigGroup(configGroup)
+ .build();
+}
+
namespace {
/* ------------------------------------------------------------------------
* Test cases
*/
TEST_F(RefreshRateStatsTest, oneConfigTest) {
- init({{CONFIG_ID_90, VSYNC_90}});
+ init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
@@ -91,8 +110,8 @@
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(0u, times.count("90fps"));
- mRefreshRateStats->setConfigMode(CONFIG_ID_90);
- mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+ mRefreshRateStats->setPowerMode(PowerMode::ON);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -100,25 +119,26 @@
ASSERT_EQ(1u, times.count("90fps"));
EXPECT_LT(0, times["90fps"]);
- mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ mRefreshRateStats->setPowerMode(PowerMode::DOZE);
int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_0);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
- // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+ // Because the power mode is not PowerMode::ON, switching the config
// does not update refresh rates that come from the config.
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
}
TEST_F(RefreshRateStatsTest, twoConfigsTest) {
- init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}});
+ init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90),
+ createConfig(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)});
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
@@ -137,8 +157,8 @@
times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_90);
- mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+ mRefreshRateStats->setPowerMode(PowerMode::ON);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -147,7 +167,7 @@
EXPECT_LT(0, times["90fps"]);
// When power mode is normal, time for configs updates.
- mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_1);
int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -156,7 +176,7 @@
ASSERT_EQ(1u, times.count("60fps"));
EXPECT_LT(0, times["60fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_0);
int sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -164,7 +184,7 @@
EXPECT_LT(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_1);
ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -172,10 +192,10 @@
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_LT(sixty, times["60fps"]);
- // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+ // Because the power mode is not PowerMode::ON, switching the config
// does not update refresh rates that come from the config.
- mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
- mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setPowerMode(PowerMode::DOZE);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_0);
sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -183,7 +203,7 @@
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
- mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_1);
screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
times = mRefreshRateStats->getTotalTimes();
@@ -194,3 +214,6 @@
} // namespace
} // namespace scheduler
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
index 160f041..f19e554 100644
--- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "RegionSamplingTest"
@@ -69,16 +73,16 @@
n++;
return pixel;
});
+
EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
- testing::FloatNear(0.083f, 0.01f));
+ testing::FloatNear(0.16f, 0.01f));
}
TEST_F(RegionSamplingTest, bimodal_tiebreaker) {
std::generate(buffer.begin(), buffer.end(),
[n = 0]() mutable { return (n++ % 2) ? kBlack : kWhite; });
- // presently there's no tiebreaking strategy in place, accept either of the means
EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
- testing::AnyOf(testing::FloatEq(1.0), testing::FloatEq(0.0f)));
+ testing::FloatEq(0.5f));
}
TEST_F(RegionSamplingTest, bounds_checking) {
@@ -137,3 +141,6 @@
}
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 571fdfd..1aa7320 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -1,3 +1,23 @@
+/*
+ * Copyright 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -10,7 +30,8 @@
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/RefreshRateConfigs.h"
-#include "Scheduler/Scheduler.h"
+#include "TestableScheduler.h"
+#include "mock/DisplayHardware/MockDisplay.h"
#include "mock/MockEventThread.h"
using testing::_;
@@ -34,38 +55,16 @@
MOCK_METHOD0(requestNextVsync, void());
};
- std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
-
- /**
- * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
- * the same.
- */
- class MockScheduler : public android::Scheduler {
- public:
- MockScheduler(const scheduler::RefreshRateConfigs& refreshRateConfigs,
- std::unique_ptr<EventThread> eventThread)
- : Scheduler([](bool) {}, refreshRateConfigs), mEventThread(std::move(eventThread)) {}
-
- std::unique_ptr<EventThread> makeEventThread(
- const char* /* connectionName */, DispSync* /* dispSync */,
- nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */,
- impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
- return std::move(mEventThread);
- }
-
- MockScheduler() = default;
- ~MockScheduler() override = default;
-
- std::unique_ptr<EventThread> mEventThread;
- };
-
SchedulerTest();
~SchedulerTest() override;
- sp<Scheduler::ConnectionHandle> mConnectionHandle;
+ std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<TestableScheduler> mScheduler;
+
+ Scheduler::ConnectionHandle mConnectionHandle;
mock::EventThread* mEventThread;
- std::unique_ptr<MockScheduler> mScheduler;
sp<MockEventThreadConnection> mEventThreadConnection;
+ Hwc2::mock::Display mDisplay;
};
SchedulerTest::SchedulerTest() {
@@ -73,14 +72,18 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
- mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfig=*/0);
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs{
+ HWC2::Display::Config::Builder(mDisplay, 0)
+ .setVsyncPeriod(int32_t(16666667))
+ .setConfigGroup(0)
+ .build()};
+ mRefreshRateConfigs = std::make_unique<
+ scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
- std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
+ mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs, false);
+
+ auto eventThread = std::make_unique<mock::EventThread>();
mEventThread = eventThread.get();
- mScheduler = std::make_unique<MockScheduler>(*mRefreshRateConfigs, std::move(eventThread));
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
mEventThreadConnection = new MockEventThreadConnection(mEventThread);
@@ -90,9 +93,8 @@
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16,
- impl::EventThread::InterceptVSyncsCallback());
- EXPECT_TRUE(mConnectionHandle != nullptr);
+ mConnectionHandle = mScheduler->createConnection(std::move(eventThread));
+ EXPECT_TRUE(mConnectionHandle);
}
SchedulerTest::~SchedulerTest() {
@@ -106,78 +108,48 @@
* Test cases
*/
-TEST_F(SchedulerTest, testNullPtr) {
- // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
- // exceptions, just gracefully continues.
- sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(
- returnedValue =
- mScheduler->createDisplayEventConnection(nullptr,
- ISurfaceComposer::
- eConfigChangedSuppress));
- EXPECT_TRUE(returnedValue == nullptr);
- EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
- EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
- ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false));
- ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
- ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
- std::string testString;
- ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString));
- EXPECT_TRUE(testString == "");
- ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10));
-}
-
TEST_F(SchedulerTest, invalidConnectionHandle) {
- // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any
- // exceptions, just gracefully continues.
- sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
+ Scheduler::ConnectionHandle handle;
- sp<IDisplayEventConnection> returnedValue;
+ sp<IDisplayEventConnection> connection;
ASSERT_NO_FATAL_FAILURE(
- returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle,
- ISurfaceComposer::
- eConfigChangedSuppress));
- EXPECT_TRUE(returnedValue == nullptr);
- EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
- EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
+ connection = mScheduler->createDisplayEventConnection(handle,
+ ISurfaceComposer::
+ eConfigChangedSuppress));
+ EXPECT_FALSE(connection);
+ EXPECT_FALSE(mScheduler->getEventConnection(handle));
// The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
- ASSERT_NO_FATAL_FAILURE(
- mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onHotplugReceived(handle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(handle));
EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(handle));
- std::string testString;
+ std::string output;
EXPECT_CALL(*mEventThread, dump(_)).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString));
- EXPECT_TRUE(testString == "");
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(handle, output));
+ EXPECT_TRUE(output.empty());
EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(handle, 10));
}
TEST_F(SchedulerTest, validConnectionHandle) {
- sp<IDisplayEventConnection> returnedValue;
+ sp<IDisplayEventConnection> connection;
ASSERT_NO_FATAL_FAILURE(
- returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle,
- ISurfaceComposer::
- eConfigChangedSuppress));
- EXPECT_TRUE(returnedValue != nullptr);
- ASSERT_EQ(returnedValue, mEventThreadConnection);
-
- EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
- EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
+ connection = mScheduler->createDisplayEventConnection(mConnectionHandle,
+ ISurfaceComposer::
+ eConfigChangedSuppress));
+ ASSERT_EQ(mEventThreadConnection, connection);
+ EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle));
EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1);
ASSERT_NO_FATAL_FAILURE(
- mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
+ mScheduler->onHotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
@@ -185,13 +157,22 @@
EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle));
- std::string testString("dump");
- EXPECT_CALL(*mEventThread, dump(testString)).Times(1);
- ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString));
- EXPECT_TRUE(testString != "");
+ std::string output("dump");
+ EXPECT_CALL(*mEventThread, dump(output)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, output));
+ EXPECT_FALSE(output.empty());
EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
+
+ static constexpr size_t kEventConnections = 5;
+ ON_CALL(*mEventThread, getEventThreadConnectionCount())
+ .WillByDefault(Return(kEventConnections));
+ EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle));
}
+
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
index 5865579..5f6a715 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "SchedulerUnittests"
@@ -128,4 +132,6 @@
} // namespace
} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
new file mode 100644
index 0000000..0d6c799
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "EffectLayer.h"
+#include "Layer.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+
+namespace android {
+
+using testing::_;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+using FrameRate = Layer::FrameRate;
+using FrameRateCompatibility = Layer::FrameRateCompatibility;
+
+class LayerFactory {
+public:
+ virtual ~LayerFactory() = default;
+
+ virtual std::string name() = 0;
+ virtual sp<Layer> createLayer(TestableSurfaceFlinger& flinger) = 0;
+
+protected:
+ static constexpr uint32_t WIDTH = 100;
+ static constexpr uint32_t HEIGHT = 100;
+ static constexpr uint32_t LAYER_FLAGS = 0;
+};
+
+class BufferQueueLayerFactory : public LayerFactory {
+public:
+ std::string name() override { return "BufferQueueLayer"; }
+ sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+ sp<Client> client;
+ LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferQueueLayer(args);
+ }
+};
+
+class BufferStateLayerFactory : public LayerFactory {
+public:
+ std::string name() override { return "BufferStateLayer"; }
+ sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+ sp<Client> client;
+ LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+ LAYER_FLAGS, LayerMetadata());
+ return new BufferStateLayer(args);
+ }
+};
+
+class EffectLayerFactory : public LayerFactory {
+public:
+ std::string name() override { return "EffectLayer"; }
+ sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+ sp<Client> client;
+ LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+ LayerMetadata());
+ return new EffectLayer(args);
+ }
+};
+
+std::string PrintToStringParamName(
+ const ::testing::TestParamInfo<std::shared_ptr<LayerFactory>>& info) {
+ return info.param->name();
+}
+
+/**
+ * This class tests the behaviour of Layer::SetFrameRate and Layer::GetFrameRate
+ */
+class SetFrameRateTest : public ::testing::TestWithParam<std::shared_ptr<LayerFactory>> {
+protected:
+ const FrameRate FRAME_RATE_VOTE1 = FrameRate(67.f, FrameRateCompatibility::Default);
+ const FrameRate FRAME_RATE_VOTE2 = FrameRate(14.f, FrameRateCompatibility::ExactOrMultiple);
+ const FrameRate FRAME_RATE_VOTE3 = FrameRate(99.f, FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_TREE = FrameRate(0, FrameRateCompatibility::NoVote);
+ const FrameRate FRAME_RATE_NO_VOTE = FrameRate(0, FrameRateCompatibility::Default);
+
+ SetFrameRateTest();
+
+ void setupScheduler();
+ void setupComposer(uint32_t virtualDisplayCount);
+
+ void addChild(sp<Layer> layer, sp<Layer> child);
+ void removeChild(sp<Layer> layer, sp<Layer> child);
+ void reparentChildren(sp<Layer> layer, sp<Layer> child);
+ void commitTransaction();
+
+ TestableSurfaceFlinger mFlinger;
+ Hwc2::mock::Composer* mComposer = nullptr;
+ mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+
+ std::vector<sp<Layer>> mLayers;
+};
+
+SetFrameRateTest::SetFrameRateTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ mFlinger.mutableUseFrameRateApi() = true;
+
+ setupScheduler();
+ setupComposer(0);
+
+ mFlinger.mutableEventQueue().reset(mMessageQueue);
+}
+void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
+ layer.get()->addChild(child.get());
+}
+
+void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) {
+ layer.get()->removeChild(child.get());
+}
+
+void SetFrameRateTest::reparentChildren(sp<Layer> parent, sp<Layer> newParent) {
+ parent.get()->reparentChildren(newParent);
+}
+
+void SetFrameRateTest::commitTransaction() {
+ for (auto layer : mLayers) {
+ layer.get()->commitTransaction(layer.get()->getCurrentState());
+ }
+}
+
+void SetFrameRateTest::setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+ EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*primaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
+ mFlinger.setupScheduler(std::move(primaryDispSync),
+ std::make_unique<mock::EventControlThread>(), std::move(eventThread),
+ std::move(sfEventThread));
+}
+
+void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) {
+ mComposer = new Hwc2::mock::Composer();
+ EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+ mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+ Mock::VerifyAndClear(mComposer);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_P(SetFrameRateTest, SetAndGet) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ layer->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParent) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParentAllVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ child1->setFrameRate(FRAME_RATE_VOTE2);
+ parent->setFrameRate(FRAME_RATE_VOTE3);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ child1->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChild) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ parent->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildAllVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ child1->setFrameRate(FRAME_RATE_VOTE2);
+ parent->setFrameRate(FRAME_RATE_VOTE3);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child1->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+
+ parent->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+ addChild(child1, child2);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ parent->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+ removeChild(child1, child2);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+ parent->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2_1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+ addChild(child1, child2_1);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetRearentChildren) {
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ const auto& layerFactory = GetParam();
+
+ auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto parent2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+ auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+ addChild(parent, child1);
+ addChild(child1, child2);
+
+ child2->setFrameRate(FRAME_RATE_VOTE1);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ reparentChildren(parent, parent2);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, parent2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+ child2->setFrameRate(FRAME_RATE_NO_VOTE);
+ commitTransaction();
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+ EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest,
+ testing::Values(std::make_shared<BufferQueueLayerFactory>(),
+ std::make_shared<BufferStateLayerFactory>(),
+ std::make_shared<EffectLayerFactory>()),
+ PrintToStringParamName);
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
new file mode 100644
index 0000000..5406879
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include "Scheduler/StrongTyping.h"
+
+using namespace testing;
+
+namespace android {
+
+TEST(StrongTypeTest, comparison) {
+ using SpunkyType = StrongTyping<int, struct SpunkyTypeTag, Compare>;
+ SpunkyType f2(22);
+ SpunkyType f1(10);
+
+ EXPECT_TRUE(f1 == f1);
+ EXPECT_TRUE(SpunkyType(10) != SpunkyType(11));
+ EXPECT_FALSE(SpunkyType(31) != SpunkyType(31));
+
+ EXPECT_TRUE(SpunkyType(10) < SpunkyType(11));
+ EXPECT_TRUE(SpunkyType(-1) < SpunkyType(0));
+ EXPECT_FALSE(SpunkyType(-10) < SpunkyType(-20));
+
+ EXPECT_TRUE(SpunkyType(10) <= SpunkyType(11));
+ EXPECT_TRUE(SpunkyType(10) <= SpunkyType(10));
+ EXPECT_TRUE(SpunkyType(-10) <= SpunkyType(1));
+ EXPECT_FALSE(SpunkyType(10) <= SpunkyType(9));
+
+ EXPECT_TRUE(SpunkyType(11) >= SpunkyType(11));
+ EXPECT_TRUE(SpunkyType(12) >= SpunkyType(11));
+ EXPECT_FALSE(SpunkyType(11) >= SpunkyType(12));
+
+ EXPECT_FALSE(SpunkyType(11) > SpunkyType(12));
+ EXPECT_TRUE(SpunkyType(-11) < SpunkyType(7));
+}
+
+TEST(StrongTypeTest, addition) {
+ using FunkyType = StrongTyping<int, struct FunkyTypeTag, Compare, Add>;
+ FunkyType f2(22);
+ FunkyType f1(10);
+
+ EXPECT_THAT(f1 + f2, Eq(FunkyType(32)));
+ EXPECT_THAT(f2 + f1, Eq(FunkyType(32)));
+
+ EXPECT_THAT(++f1.value(), Eq(11));
+ EXPECT_THAT(f1.value(), Eq(11));
+ EXPECT_THAT(f1++.value(), Eq(11));
+ EXPECT_THAT(f1++.value(), Eq(12));
+ EXPECT_THAT(f1.value(), Eq(13));
+
+ auto f3 = f1;
+ EXPECT_THAT(f1, Eq(f3));
+ EXPECT_THAT(f1, Lt(f2));
+
+ f3 += f1;
+ EXPECT_THAT(f1.value(), Eq(13));
+ EXPECT_THAT(f3.value(), Eq(26));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index cb6980e..d5ecae8 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -19,30 +19,49 @@
#include <gmock/gmock.h>
#include <gui/ISurfaceComposer.h>
+#include "Scheduler/DispSync.h"
#include "Scheduler/EventThread.h"
-#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/LayerHistory.h"
#include "Scheduler/Scheduler.h"
namespace android {
-class TestableScheduler : public Scheduler {
+class TestableScheduler : public Scheduler, private ISchedulerCallback {
public:
- TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig)
- : Scheduler([](bool) {}, refreshRateConfig) {}
+ TestableScheduler(const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2)
+ : Scheduler([](bool) {}, configs, *this, useContentDetectionV2, true) {
+ if (mUseContentDetectionV2) {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(configs);
+ } else {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ }
+ }
- // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
- // and adds it to the list of connectins. Returns the ConnectionHandle for the
- // Scheduler::Connection. This allows plugging in mock::EventThread.
- sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
- sp<EventThreadConnection> eventThreadConnection =
- new EventThreadConnection(eventThread.get(), ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress);
- const int64_t id = sNextId++;
- mConnections.emplace(id,
- std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
- eventThreadConnection,
- std::move(eventThread)));
- return mConnections[id]->handle;
+ TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2)
+ : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this,
+ useContentDetectionV2, true) {
+ if (mUseContentDetectionV2) {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(configs);
+ } else {
+ mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+ }
+ }
+
+ // Used to inject mock event thread.
+ ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
+ return Scheduler::createConnection(std::move(eventThread));
+ }
+
+ size_t layerHistorySize() const NO_THREAD_SAFETY_ANALYSIS {
+ if (mUseContentDetectionV2) {
+ return static_cast<scheduler::impl::LayerHistoryV2*>(mLayerHistory.get())
+ ->mLayerInfos.size();
+ } else {
+ return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get())
+ ->mLayerInfos.size();
+ }
}
/* ------------------------------------------------------------------------
@@ -53,6 +72,12 @@
auto& mutableEventControlThread() { return mEventControlThread; }
auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+ auto mutableLayerHistory() {
+ return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get());
+ }
+ auto mutableLayerHistoryV2() {
+ return static_cast<scheduler::impl::LayerHistoryV2*>(mLayerHistory.get());
+ }
~TestableScheduler() {
// All these pointer and container clears help ensure that GMock does
@@ -62,7 +87,12 @@
mutableEventControlThread().reset();
mutablePrimaryDispSync().reset();
mConnections.clear();
- };
+ }
+
+private:
+ void changeRefreshRate(const RefreshRate&, ConfigEvent) override {}
+ void repaintEverythingForHWC() override {}
+ void kernelTimerChanged(bool /*expired*/) override {}
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 1c1b020..38bc8a1 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,17 +17,18 @@
#pragma once
#include <compositionengine/Display.h>
-#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
-#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <compositionengine/mock/DisplaySurface.h>
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
-#include "ColorLayer.h"
#include "ContainerLayer.h"
#include "DisplayDevice.h"
+#include "EffectLayer.h"
#include "FakePhaseOffsets.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
@@ -35,9 +36,10 @@
#include "Scheduler/RefreshRateConfigs.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
-#include "SurfaceFlingerFactory.h"
+#include "SurfaceFlingerDefaultFactory.h"
#include "SurfaceInterceptor.h"
-#include "TimeStats/TimeStats.h"
+#include "TestableScheduler.h"
+#include "mock/DisplayHardware/MockDisplay.h"
namespace android {
@@ -55,72 +57,82 @@
} // namespace Hwc2
+namespace hal = android::hardware::graphics::composer::hal;
+
namespace surfaceflinger::test {
class Factory final : public surfaceflinger::Factory {
public:
~Factory() = default;
- std::unique_ptr<DispSync> createDispSync(const char*, bool, int64_t) override {
- // TODO: Use test-fixture controlled factory
+ std::unique_ptr<DispSync> createDispSync(const char*, bool) override {
return nullptr;
}
std::unique_ptr<EventControlThread> createEventControlThread(
std::function<void(bool)>) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
std::unique_ptr<MessageQueue> createMessageQueue() override {
- // TODO: Use test-fixture controlled factory
return std::make_unique<android::impl::MessageQueue>();
}
- std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+ std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+ const scheduler::RefreshRateConfigs& /*refreshRateConfigs*/) override {
return std::make_unique<scheduler::FakePhaseOffsets>();
}
std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>,
- const scheduler::RefreshRateConfigs&) override {
- // TODO: Use test-fixture controlled factory
+ const scheduler::RefreshRateConfigs&,
+ ISchedulerCallback&) override {
return nullptr;
}
std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
- // TODO: Use test-fixture controlled factory
return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
}
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
- // TODO: Use test-fixture controlled factory
return new StartPropertySetThread(timestampPropertyValue);
}
- sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
- // TODO: Use test-fixture controlled factory
- return new DisplayDevice(std::move(creationArgs));
+ sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override {
+ return new DisplayDevice(creationArgs);
}
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
std::string requestorName) override {
- // TODO: Use test-fixture controlled factory
return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
}
void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
sp<IGraphicBufferConsumer>* outConsumer,
bool consumerIsSurfaceFlinger) override {
- if (!mCreateBufferQueue) return;
+ if (!mCreateBufferQueue) {
+ BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+ return;
+ }
mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
}
+ sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>& producer,
+ const sp<SurfaceFlinger>& flinger,
+ const wp<Layer>& layer) override {
+ return new MonitoredProducer(producer, flinger, layer);
+ }
+
+ sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>& consumer,
+ renderengine::RenderEngine& renderEngine,
+ uint32_t textureName, Layer* layer) override {
+ return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
+ }
+
std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
const sp<IGraphicBufferProducer>& producer) override {
if (!mCreateNativeWindowSurface) return nullptr;
@@ -132,30 +144,19 @@
}
sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
- sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
- return nullptr;
- }
+ sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
- // TODO: Use test-fixture controlled factory
return nullptr;
}
- std::shared_ptr<TimeStats> createTimeStats() override {
- // TODO: Use test-fixture controlled factory
- return std::make_shared<android::impl::TimeStats>();
- }
-
using CreateBufferQueueFunction =
std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
sp<IGraphicBufferConsumer>* /* outConsumer */,
@@ -176,6 +177,11 @@
class TestableSurfaceFlinger {
public:
+ using HotplugEvent = SurfaceFlinger::HotplugEvent;
+
+ SurfaceFlinger* flinger() { return mFlinger.get(); }
+ TestableScheduler* scheduler() { return mScheduler; }
+
// Extend this as needed for accessing SurfaceFlinger private (and public)
// functions.
@@ -188,6 +194,45 @@
std::make_unique<impl::HWComposer>(std::move(composer)));
}
+ void setupTimeStats(const std::shared_ptr<TimeStats>& timeStats) {
+ mFlinger->mCompositionEngine->setTimeStats(timeStats);
+ }
+
+ void setupScheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ std::unique_ptr<EventThread> appEventThread,
+ std::unique_ptr<EventThread> sfEventThread,
+ bool useContentDetectionV2 = false) {
+ std::vector<std::shared_ptr<const HWC2::Display::Config>> configs{
+ HWC2::Display::Config::Builder(mDisplay, 0)
+ .setVsyncPeriod(int32_t(16666667))
+ .setConfigGroup(0)
+ .build()};
+
+ mFlinger->mRefreshRateConfigs = std::make_unique<
+ scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
+ mFlinger->mRefreshRateStats = std::make_unique<
+ scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
+ /*currentConfig=*/HwcConfigIndexType(0),
+ /*powerMode=*/hal::PowerMode::OFF);
+ mFlinger->mPhaseConfiguration =
+ mFactory.createPhaseConfiguration(*mFlinger->mRefreshRateConfigs);
+
+ mScheduler =
+ new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread),
+ *mFlinger->mRefreshRateConfigs, useContentDetectionV2);
+
+ mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
+ mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
+ resetScheduler(mScheduler);
+
+ mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
+ mFlinger->mSfConnectionHandle,
+ mFlinger->mPhaseConfiguration->getCurrentOffsets());
+ }
+
+ void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
+
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
mFactory.mCreateBufferQueue = f;
@@ -203,26 +248,32 @@
memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries));
}
- using HotplugEvent = SurfaceFlinger::HotplugEvent;
+ static auto& mutableLayerCurrentState(const sp<Layer>& layer) { return layer->mCurrentState; }
+ static auto& mutableLayerDrawingState(const sp<Layer>& layer) { return layer->mDrawingState; }
- auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
- auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
+ auto& mutableStateLock() { return mFlinger->mStateLock; }
- void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
- layer->mDrawingState.sidebandStream = sidebandStream;
- layer->mSidebandStream = sidebandStream;
- layer->getCompositionLayer()->editState().frontEnd.sidebandStream = sidebandStream;
+ static auto findOutputLayerForDisplay(const sp<Layer>& layer,
+ const sp<const DisplayDevice>& display) {
+ return layer->findOutputLayerForDisplay(display.get());
}
- void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
- auto outputLayer = layer->findOutputLayerForDisplay(mFlinger->getDefaultDisplayDevice());
+ static void setLayerSidebandStream(const sp<Layer>& layer,
+ const sp<NativeHandle>& sidebandStream) {
+ layer->mDrawingState.sidebandStream = sidebandStream;
+ layer->mSidebandStream = sidebandStream;
+ layer->editCompositionState()->sidebandStream = sidebandStream;
+ }
+
+ void setLayerCompositionType(const sp<Layer>& layer, hal::Composition type) {
+ auto outputLayer = findOutputLayerForDisplay(layer, mFlinger->getDefaultDisplayDevice());
LOG_ALWAYS_FATAL_IF(!outputLayer);
auto& state = outputLayer->editState();
LOG_ALWAYS_FATAL_IF(!outputLayer->getState().hwc);
- (*state.hwc).hwcCompositionType = static_cast<Hwc2::IComposerClient::Composition>(type);
- };
+ (*state.hwc).hwcCompositionType = type;
+ }
- void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
+ static void setLayerPotentialCursor(const sp<Layer>& layer, bool potentialCursor) {
layer->mPotentialCursor = potentialCursor;
}
@@ -238,15 +289,16 @@
return mFlinger->destroyDisplay(displayToken);
}
- auto resetDisplayState() { return mFlinger->resetDisplayState(); }
+ auto resetDisplayState() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->resetDisplayState(); }
- auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
- const std::optional<DisplayId>& displayId,
- const DisplayDeviceState& state,
- const sp<compositionengine::DisplaySurface>& dispSurface,
- const sp<IGraphicBufferProducer>& producer) {
- return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface,
- producer);
+ auto setupNewDisplayDeviceInternal(
+ const wp<IBinder>& displayToken,
+ std::shared_ptr<compositionengine::Display> compositionDisplay,
+ const DisplayDeviceState& state,
+ const sp<compositionengine::DisplaySurface>& dispSurface,
+ const sp<IGraphicBufferProducer>& producer) NO_THREAD_SAFETY_ANALYSIS {
+ return mFlinger->setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
+ dispSurface, producer);
}
auto handleTransactionLocked(uint32_t transactionFlags) {
@@ -254,8 +306,8 @@
return mFlinger->handleTransactionLocked(transactionFlags);
}
- auto onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
- HWC2::Connection connection) {
+ auto onHotplugReceived(int32_t sequenceId, hal::HWDisplayId display,
+ hal::Connection connection) {
return mFlinger->onHotplugReceived(sequenceId, display, connection);
}
@@ -271,19 +323,20 @@
// Allow reading display state without locking, as if called on the SF main thread.
auto setPowerModeInternal(const sp<DisplayDevice>& display,
- int mode) NO_THREAD_SAFETY_ANALYSIS {
+ hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
return mFlinger->setPowerModeInternal(display, mode);
}
- auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); }
+ auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what, systemTime()); }
- auto captureScreenImplLocked(
- const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers,
- ANativeWindowBuffer* buffer, bool useIdentityTransform, bool forSystem, int* outSyncFd) {
+ auto captureScreenImplLocked(const RenderArea& renderArea,
+ SurfaceFlinger::TraverseLayersFunction traverseLayers,
+ ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ bool forSystem, int* outSyncFd, bool regionSampling) {
bool ignored;
return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
useIdentityTransform, forSystem, outSyncFd,
- ignored);
+ regionSampling, ignored);
}
auto traverseLayersInDisplay(const sp<const DisplayDevice>& display,
@@ -296,6 +349,22 @@
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
+ auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
+
+ auto setTransactionState(const Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+ bool hasListenerCallbacks,
+ std::vector<ListenerCallbacks>& listenerCallbacks) {
+ return mFlinger->setTransactionState(states, displays, flags, applyToken,
+ inputWindowCommands, desiredPresentTime, uncacheBuffer,
+ hasListenerCallbacks, listenerCallbacks);
+ }
+
+ auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+
/* ------------------------------------------------------------------------
* Read-only access to private data to assert post-conditions.
*/
@@ -306,6 +375,7 @@
auto& getHwComposer() const {
return static_cast<impl::HWComposer&>(mFlinger->getHwComposer());
}
+ auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); }
const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
@@ -315,7 +385,6 @@
*/
auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
- auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
auto& mutableCurrentState() { return mFlinger->mCurrentState; }
@@ -332,18 +401,18 @@
auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
+ auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
- auto& mutableScheduler() { return mFlinger->mScheduler; }
- auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
- auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
- auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; }
- auto& mutableRefreshRateStats() { return mFlinger->mRefreshRateStats; }
- auto& mutableTimeStats() { return mFlinger->mTimeStats; }
+ auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
+
+ auto fromHandle(const sp<IBinder>& handle) {
+ return mFlinger->fromHandle(handle);
+ }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -355,7 +424,7 @@
mutableDrawingState().displays.clear();
mutableEventQueue().reset();
mutableInterceptor().reset();
- mutableScheduler().reset();
+ mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
std::unique_ptr<renderengine::RenderEngine>());
@@ -367,12 +436,12 @@
*/
struct HWC2Display : public HWC2::impl::Display {
HWC2Display(Hwc2::Composer& composer,
- const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
- HWC2::DisplayType type)
+ const std::unordered_set<hal::Capability>& capabilities, hal::HWDisplayId id,
+ hal::DisplayType type)
: HWC2::impl::Display(composer, capabilities, id, type) {}
~HWC2Display() {
// Prevents a call to disable vsyncs.
- mType = HWC2::DisplayType::Invalid;
+ mType = hal::DisplayType::INVALID;
}
auto& mutableIsConnected() { return this->mIsConnected; }
@@ -382,19 +451,19 @@
class FakeHwcDisplayInjector {
public:
- static constexpr hwc2_display_t DEFAULT_HWC_DISPLAY_ID = 1000;
+ static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000;
static constexpr int32_t DEFAULT_WIDTH = 1920;
static constexpr int32_t DEFAULT_HEIGHT = 1280;
static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+ static constexpr int32_t DEFAULT_CONFIG_GROUP = 7;
static constexpr int32_t DEFAULT_DPI = 320;
- static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
- static constexpr int32_t DEFAULT_POWER_MODE = 2;
+ static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0;
+ static constexpr hal::PowerMode DEFAULT_POWER_MODE = hal::PowerMode::ON;
- FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
- bool isPrimary)
+ FakeHwcDisplayInjector(DisplayId displayId, hal::DisplayType hwcDisplayType, bool isPrimary)
: mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {}
- auto& setHwcDisplayId(hwc2_display_t displayId) {
+ auto& setHwcDisplayId(hal::HWDisplayId displayId) {
mHwcDisplayId = displayId;
return *this;
}
@@ -424,23 +493,23 @@
return *this;
}
- auto& setActiveConfig(int32_t config) {
+ auto& setActiveConfig(hal::HWConfigId config) {
mActiveConfig = config;
return *this;
}
- auto& setCapabilities(const std::unordered_set<HWC2::Capability>* capabilities) {
+ auto& setCapabilities(const std::unordered_set<hal::Capability>* capabilities) {
mCapabilities = capabilities;
return *this;
}
- auto& setPowerMode(int mode) {
+ auto& setPowerMode(hal::PowerMode mode) {
mPowerMode = mode;
return *this;
}
void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
- static const std::unordered_set<HWC2::Capability> defaultCapabilities;
+ static const std::unordered_set<hal::Capability> defaultCapabilities;
if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
// Caution - Make sure that any values passed by reference here do
@@ -456,44 +525,47 @@
config.setVsyncPeriod(mRefreshRate);
config.setDpiX(mDpiX);
config.setDpiY(mDpiY);
- display->mutableConfigs().emplace(mActiveConfig, config.build());
+ config.setConfigGroup(mConfigGroup);
+ display->mutableConfigs().emplace(static_cast<int32_t>(mActiveConfig), config.build());
display->mutableIsConnected() = true;
- display->setPowerMode(static_cast<HWC2::PowerMode>(mPowerMode));
+ display->setPowerMode(mPowerMode);
- flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
+ flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
- if (mHwcDisplayType == HWC2::DisplayType::Physical) {
+ if (mHwcDisplayType == hal::DisplayType::PHYSICAL) {
flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId);
(mIsPrimary ? flinger->mutableInternalHwcDisplayId()
: flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
}
-
- flinger->mFakeHwcDisplays.push_back(std::move(display));
}
private:
const DisplayId mDisplayId;
- const HWC2::DisplayType mHwcDisplayType;
+ const hal::DisplayType mHwcDisplayType;
const bool mIsPrimary;
- hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
+ hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
int32_t mWidth = DEFAULT_WIDTH;
int32_t mHeight = DEFAULT_HEIGHT;
int32_t mRefreshRate = DEFAULT_REFRESH_RATE;
int32_t mDpiX = DEFAULT_DPI;
+ int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
int32_t mDpiY = DEFAULT_DPI;
- int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
- int32_t mPowerMode = DEFAULT_POWER_MODE;
- const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
+ hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
+ hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
+ const std::unordered_set<hal::Capability>* mCapabilities = nullptr;
};
class FakeDisplayDeviceInjector {
public:
FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
- const std::optional<DisplayId>& displayId, bool isVirtual,
- bool isPrimary)
- : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
- mCreationArgs.isVirtual = isVirtual;
+ std::shared_ptr<compositionengine::Display> compositionDisplay,
+ std::optional<DisplayConnectionType> connectionType,
+ std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
+ : mFlinger(flinger),
+ mCreationArgs(flinger.mFlinger.get(), mDisplayToken, compositionDisplay),
+ mHwcDisplayId(hwcDisplayId) {
+ mCreationArgs.connectionType = connectionType;
mCreationArgs.isPrimary = isPrimary;
}
@@ -532,7 +604,7 @@
return *this;
}
- auto& setPowerMode(int mode) {
+ auto& setPowerMode(hal::PowerMode mode) {
mCreationArgs.initialPowerMode = mode;
return *this;
}
@@ -549,19 +621,30 @@
return *this;
}
+ auto& setPhysicalOrientation(ui::Rotation orientation) {
+ mCreationArgs.physicalOrientation = orientation;
+ return *this;
+ }
+
sp<DisplayDevice> inject() {
+ const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
+
DisplayDeviceState state;
- state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
+ if (const auto type = mCreationArgs.connectionType) {
+ LOG_ALWAYS_FATAL_IF(!displayId);
+ LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
+ state.physical = {*displayId, *type, *mHwcDisplayId};
+ }
+
state.isSecure = mCreationArgs.isSecure;
- sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
+ sp<DisplayDevice> device = new DisplayDevice(mCreationArgs);
mFlinger.mutableDisplays().emplace(mDisplayToken, device);
mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
- if (!mCreationArgs.isVirtual) {
- LOG_ALWAYS_FATAL_IF(!state.displayId);
- mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
+ if (const auto& physical = state.physical) {
+ mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
}
return device;
@@ -571,13 +654,13 @@
TestableSurfaceFlinger& mFlinger;
sp<BBinder> mDisplayToken = new BBinder();
DisplayDeviceCreationArgs mCreationArgs;
+ const std::optional<hal::HWDisplayId> mHwcDisplayId;
};
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
-
- // We need to keep a reference to these so they are properly destroyed.
- std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
+ TestableScheduler* mScheduler = nullptr;
+ Hwc2::mock::Display mDisplay;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index f35758d..0a24650 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -14,33 +14,45 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <TimeStats/TimeStats.h>
+#include <android/util/ProtoOutputStream.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <chrono>
#include <random>
#include <unordered_set>
-#include "TimeStats/TimeStats.h"
-
#include "libsurfaceflinger_unittest_main.h"
using namespace android::surfaceflinger;
using namespace google::protobuf;
+using namespace std::chrono_literals;
namespace android {
namespace {
+using testing::_;
+using testing::AnyNumber;
using testing::Contains;
+using testing::HasSubstr;
+using testing::InSequence;
using testing::SizeIs;
+using testing::StrEq;
using testing::UnorderedElementsAre;
+using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
+
// clang-format off
#define FMT_PROTO true
#define FMT_STRING false
@@ -133,7 +145,44 @@
}
std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
- std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
+
+ class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
+ public:
+ FakeStatsEventDelegate() = default;
+ ~FakeStatsEventDelegate() override = default;
+
+ struct AStatsEvent* addStatsEventToPullData(AStatsEventList*) override {
+ return mEvent;
+ }
+ void setStatsPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata*,
+ AStatsManager_PullAtomCallback callback,
+ void* cookie) override {
+ mAtomTags.push_back(atom_tag);
+ mCallback = callback;
+ mCookie = cookie;
+ }
+
+ AStatsManager_PullAtomCallbackReturn makePullAtomCallback(int32_t atom_tag, void* cookie) {
+ return (*mCallback)(atom_tag, nullptr, cookie);
+ }
+
+ MOCK_METHOD1(clearStatsPullAtomCallback, void(int32_t));
+ MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t));
+ MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_t));
+ MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t));
+ MOCK_METHOD2(statsEventWriteString8, void(AStatsEvent*, const char*));
+ MOCK_METHOD3(statsEventWriteByteArray, void(AStatsEvent*, const uint8_t*, size_t));
+ MOCK_METHOD1(statsEventBuild, void(AStatsEvent*));
+
+ AStatsEvent* mEvent = AStatsEvent_obtain();
+ std::vector<int32_t> mAtomTags;
+ AStatsManager_PullAtomCallback mCallback = nullptr;
+ void* mCookie = nullptr;
+ };
+ FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
+ std::unique_ptr<TimeStats> mTimeStats =
+ std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+ std::nullopt, std::nullopt);
};
std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -171,8 +220,8 @@
return result;
}
-static std::string genLayerName(int32_t layerID) {
- return (layerID < 0 ? "invalid.dummy" : "com.dummy#") + std::to_string(layerID);
+static std::string genLayerName(int32_t layerId) {
+ return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.example.fake#") + std::to_string(layerId);
}
void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
@@ -210,6 +259,25 @@
return distr(mRandomEngine);
}
+TEST_F(TimeStatsTest, disabledByDefault) {
+ ASSERT_FALSE(mTimeStats->isEnabled());
+}
+
+TEST_F(TimeStatsTest, setsCallbacksAfterBoot) {
+ mTimeStats->onBootFinished();
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+}
+
+TEST_F(TimeStatsTest, clearsCallbacksOnDestruction) {
+ EXPECT_CALL(*mDelegate,
+ clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate,
+ clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ mTimeStats.reset();
+}
+
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
@@ -246,6 +314,125 @@
EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
}
+TEST_F(TimeStatsTest, canIncreaseLateAcquireFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t LATE_ACQUIRE_FRAMES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
+ mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
+ }
+ insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult = "lateAcquireFrames = " + std::to_string(LATE_ACQUIRE_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseBadDesiredPresent) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
+ mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
+ }
+ insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "badDesiredPresentFrames = " + std::to_string(BAD_DESIRED_PRESENT_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ }
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t REFRESH_RATE_SWITCHES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ for (size_t i = 0; i < REFRESH_RATE_SWITCHES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
+ }
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "refreshRateSwitches = " + std::to_string(REFRESH_RATE_SWITCHES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
+ }
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canAverageFrameDuration) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ mTimeStats->setPowerMode(PowerMode::ON);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(16ms)
+ .count());
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("averageFrameDuration = 10.000 ms"));
+}
+
+TEST_F(TimeStatsTest, canAverageRenderEngineTimings) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
+ .count(),
+ std::make_shared<FenceTime>(
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(3ms)
+ .count()));
+
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(8ms)
+ .count());
+
+ // Push a fake present fence to trigger flushing the RenderEngine timings.
+ mTimeStats->setPowerMode(PowerMode::ON);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 3.000 ms"));
+}
+
TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -254,13 +441,13 @@
ASSERT_NO_FATAL_FAILURE(
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
- ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
ASSERT_NO_FATAL_FAILURE(
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
ASSERT_NO_FATAL_FAILURE(
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
- ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_OFF));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::OFF));
ASSERT_NO_FATAL_FAILURE(
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
ASSERT_NO_FATAL_FAILURE(
@@ -275,6 +462,65 @@
EXPECT_EQ(2, histogramProto.time_millis());
}
+TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->setPowerMode(PowerMode::OFF);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
+ .count());
+ mTimeStats->setPowerMode(PowerMode::ON);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ ASSERT_EQ(1, globalProto.frame_duration_size());
+ const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.frame_duration().Get(0);
+ EXPECT_EQ(1, histogramProto.frame_count());
+ EXPECT_EQ(3, histogramProto.time_millis());
+}
+
+TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
+ .count(),
+ std::make_shared<FenceTime>(
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(3ms)
+ .count()));
+
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+
+ // First verify that flushing RenderEngine durations did not occur yet.
+ SFTimeStatsGlobalProto preFlushProto;
+ ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+ ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
+
+ // Push a fake present fence to trigger flushing the RenderEngine timings.
+ mTimeStats->setPowerMode(PowerMode::ON);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+
+ // Now we can verify that RenderEngine durations were flushed now.
+ SFTimeStatsGlobalProto postFlushProto;
+ ASSERT_TRUE(postFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ ASSERT_EQ(1, postFlushProto.render_engine_timing_size());
+ const SFTimeStatsHistogramBucketProto& histogramProto =
+ postFlushProto.render_engine_timing().Get(0);
+ EXPECT_EQ(2, histogramProto.frame_count());
+ EXPECT_EQ(2, histogramProto.time_millis());
+}
+
TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -495,7 +741,16 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
- ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
+
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
ASSERT_NO_FATAL_FAILURE(
mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
ASSERT_NO_FATAL_FAILURE(
@@ -512,9 +767,38 @@
EXPECT_EQ(0, globalProto.missed_frames());
EXPECT_EQ(0, globalProto.client_composition_frames());
EXPECT_EQ(0, globalProto.present_to_present_size());
+ EXPECT_EQ(0, globalProto.frame_duration_size());
+ EXPECT_EQ(0, globalProto.render_engine_timing_size());
EXPECT_EQ(0, globalProto.stats_size());
}
+TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
+ // These stats are not in the proto so verify by checking the string dump.
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
+ mTimeStats->setPowerMode(PowerMode::ON);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
+ .count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+ EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
+ EXPECT_THAT(result, HasSubstr("refreshRateSwitches = 0"));
+ EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
+ EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
+ EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
+}
+
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -549,6 +833,359 @@
ASSERT_EQ(0, globalProto.stats_size());
}
+TEST_F(TimeStatsTest, noInfInAverageFPS) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 1000000);
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("averageFPS = 0.000"));
+}
+
+namespace {
+std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
+ const std::vector<int32_t>& frameCounts) {
+ util::ProtoOutputStream proto;
+ for (int i = 0; i < times.size(); i++) {
+ ALOGE("Writing time: %d", times[i]);
+ proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */,
+ (int32_t)times[i]);
+ ALOGE("Writing count: %d", frameCounts[i]);
+ proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */,
+ (int64_t)frameCounts[i]);
+ }
+ std::string byteString;
+ proto.serializeToString(&byteString);
+ return byteString;
+}
+
+std::string dumpByteStringHex(const std::string& str) {
+ std::stringstream ss;
+ ss << std::hex;
+ for (const char& c : str) {
+ ss << (int)c << " ";
+ }
+
+ return ss.str();
+}
+
+} // namespace
+
+MATCHER_P2(BytesEq, bytes, size, "") {
+ std::string expected;
+ expected.append((const char*)bytes, size);
+ std::string actual;
+ actual.append((const char*)arg, size);
+
+ *result_listener << "Bytes are not equal! \n";
+ *result_listener << "size: " << size << "\n";
+ *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n";
+ *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n";
+
+ return expected == actual;
+}
+
+TEST_F(TimeStatsTest, globalStatsCallback) {
+ constexpr size_t TOTAL_FRAMES = 5;
+ constexpr size_t MISSED_FRAMES = 4;
+ constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+ constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
+
+ mTimeStats->onBootFinished();
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+ mTimeStats->incrementTotalFrames();
+ }
+ for (size_t i = 0; i < MISSED_FRAMES; i++) {
+ mTimeStats->incrementMissedFrames();
+ }
+ for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+ mTimeStats->incrementClientCompositionFrames();
+ }
+
+ mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
+ mTimeStats->setPowerMode(PowerMode::ON);
+ mTimeStats->recordFrameDuration(1000000, 3000000);
+ mTimeStats->recordRenderEngineDuration(2000000, 4000000);
+ mTimeStats->recordRenderEngineDuration(2000000, std::make_shared<FenceTime>(3000000));
+
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
+ std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
+
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedFrameDuration.c_str(),
+ expectedFrameDuration.size()),
+ expectedFrameDuration.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedRenderEngineTiming.c_str(),
+ expectedRenderEngineTiming.size()),
+ expectedRenderEngineTiming.size()));
+ EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+ }
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ mDelegate->mCookie));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ EXPECT_EQ(0, globalProto.total_frames());
+ EXPECT_EQ(0, globalProto.missed_frames());
+ EXPECT_EQ(0, globalProto.client_composition_frames());
+ EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
+ constexpr size_t LATE_ACQUIRE_FRAMES = 2;
+ constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
+ mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
+ }
+ for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
+ mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
+ }
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1});
+ std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1});
+ std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1});
+ std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1});
+ std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
+ std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent,
+ StrEq(genLayerName(LAYER_ID_0).c_str())));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedPresentToPresent.c_str(),
+ expectedPresentToPresent.size()),
+ expectedPresentToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedPostToPresent.c_str(),
+ expectedPostToPresent.size()),
+ expectedPostToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedAcquireToPresent.c_str(),
+ expectedAcquireToPresent.size()),
+ expectedAcquireToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedLatchToPresent.c_str(),
+ expectedLatchToPresent.size()),
+ expectedLatchToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedDesiredToPresent.c_str(),
+ expectedDesiredToPresent.size()),
+ expectedDesiredToPresent.size()));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
+ expectedPostToAcquire.size()),
+ expectedPostToAcquire.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES));
+ EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+ }
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+
+ SFTimeStatsGlobalProto globalProto;
+ ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+ EXPECT_EQ(0, globalProto.stats_size());
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+ .Times(2);
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str())));
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+ // Now make sure that TimeStats flushes global stats to set the callback.
+ mTimeStats->setPowerMode(PowerMode::ON);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1});
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedPresentToPresent.c_str(),
+ expectedPresentToPresent.size()),
+ expectedPresentToPresent.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+ .Times(AnyNumber());
+ }
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
+ mDelegate = new FakeStatsEventDelegate;
+ mTimeStats =
+ std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+ std::nullopt, 1);
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2});
+ {
+ InSequence seq;
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteByteArray(mDelegate->mEvent,
+ BytesEq((const uint8_t*)
+ expectedPresentToPresent.c_str(),
+ expectedPresentToPresent.size()),
+ expectedPresentToPresent.size()));
+ EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+ .Times(AnyNumber());
+ }
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
+ mDelegate = new FakeStatsEventDelegate;
+ mTimeStats =
+ std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1,
+ std::nullopt);
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ mTimeStats->onBootFinished();
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
+
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ EXPECT_NE(nullptr, mDelegate->mCallback);
+ EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+ EXPECT_CALL(*mDelegate,
+ statsEventSetAtomId(mDelegate->mEvent,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+ .Times(1);
+ EXPECT_CALL(*mDelegate,
+ statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+ EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+ mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ mDelegate->mCookie));
+}
+
TEST_F(TimeStatsTest, canSurviveMonkey) {
if (g_noSlowTests) {
GTEST_SKIP();
@@ -557,24 +1194,27 @@
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
for (size_t i = 0; i < 10000000; ++i) {
- const int32_t layerID = genRandomInt32(-1, 10);
+ const int32_t layerId = genRandomInt32(-1, 10);
const int32_t frameNumber = genRandomInt32(1, 10);
switch (genRandomInt32(0, 100)) {
case 0:
ALOGV("removeTimeRecord");
- ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerID, frameNumber));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerId, frameNumber));
continue;
case 1:
ALOGV("onDestroy");
- ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerID));
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerId));
continue;
}
TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
const int32_t ts = genRandomInt32(1, 1000000000);
- ALOGV("type[%d], layerID[%d], frameNumber[%d], ts[%d]", type, layerID, frameNumber, ts);
- setTimeStamp(type, layerID, frameNumber, ts);
+ ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts);
+ setTimeStamp(type, layerId, frameNumber, ts);
}
}
} // namespace
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
new file mode 100644
index 0000000..2a48a22
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "CompositionTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+
+namespace android {
+
+using testing::_;
+using testing::Return;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+class TransactionApplicationTest : public testing::Test {
+public:
+ TransactionApplicationTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ mFlinger.mutableEventQueue().reset(mMessageQueue);
+ setupScheduler();
+ }
+
+ ~TransactionApplicationTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void setupScheduler() {
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
+
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(
+ new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(
+ new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+ mFlinger.setupScheduler(std::unique_ptr<mock::DispSync>(mPrimaryDispSync),
+ std::make_unique<mock::EventControlThread>(),
+ std::move(eventThread), std::move(sfEventThread));
+ }
+
+ TestableScheduler* mScheduler;
+ TestableSurfaceFlinger mFlinger;
+
+ std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
+ mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+ mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+ struct TransactionInfo {
+ Vector<ComposerState> states;
+ Vector<DisplayState> displays;
+ uint32_t flags = 0;
+ sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+ InputWindowCommands inputWindowCommands;
+ int64_t desiredPresentTime = -1;
+ client_cache_t uncacheBuffer;
+ };
+
+ void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
+ EXPECT_EQ(0, info.states.size());
+ EXPECT_EQ(0, state.states.size());
+
+ EXPECT_EQ(0, info.displays.size());
+ EXPECT_EQ(0, state.displays.size());
+ EXPECT_EQ(info.flags, state.flags);
+ EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
+ }
+
+ void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
+ int64_t desiredPresentTime) {
+ mTransactionNumber++;
+ transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
+ transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
+ transaction.desiredPresentTime = desiredPresentTime;
+ }
+
+ void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ // called in SurfaceFlinger::signalTransaction
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)).WillOnce(Return(systemTime()));
+ TransactionInfo transaction;
+ setupSingle(transaction, flags, syncInputWindows,
+ /*desiredPresentTime*/ -1);
+ nsecs_t applicationTime = systemTime();
+ mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime, transaction.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks);
+
+ // This transaction should not have been placed on the transaction queue.
+ // If transaction is synchronous or syncs input windows, SF
+ // applyTransactionState should time out (5s) wating for SF to commit
+ // the transaction or to receive a signal that syncInputWindows has
+ // completed. If this is animation, it should not time out waiting.
+ nsecs_t returnedTime = systemTime();
+ if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) {
+ EXPECT_GE(returnedTime, applicationTime + s2ns(5));
+ } else {
+ EXPECT_LE(returnedTime, applicationTime + s2ns(5));
+ }
+ auto transactionQueue = mFlinger.getTransactionQueue();
+ EXPECT_EQ(0, transactionQueue.size());
+ }
+
+ void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ // called in SurfaceFlinger::signalTransaction
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ // first check will see desired present time has not passed,
+ // but afterwards it will look like the desired present time has passed
+ nsecs_t time = systemTime();
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
+ .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+ TransactionInfo transaction;
+ setupSingle(transaction, flags, syncInputWindows,
+ /*desiredPresentTime*/ time + s2ns(1));
+ nsecs_t applicationSentTime = systemTime();
+ mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+ transaction.applyToken, transaction.inputWindowCommands,
+ transaction.desiredPresentTime, transaction.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks);
+
+ nsecs_t returnedTime = systemTime();
+ EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
+ // This transaction should have been placed on the transaction queue
+ auto transactionQueue = mFlinger.getTransactionQueue();
+ EXPECT_EQ(1, transactionQueue.size());
+ }
+
+ void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ // called in SurfaceFlinger::signalTransaction
+ nsecs_t time = systemTime();
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
+ .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+ // transaction that should go on the pending thread
+ TransactionInfo transactionA;
+ setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ time + s2ns(1));
+
+ // transaction that would not have gone on the pending thread if not
+ // blocked
+ TransactionInfo transactionB;
+ setupSingle(transactionB, flags, syncInputWindows,
+ /*desiredPresentTime*/ -1);
+
+ nsecs_t applicationSentTime = systemTime();
+ mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+ transactionA.applyToken, transactionA.inputWindowCommands,
+ transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks);
+
+ // This thread should not have been blocked by the above transaction
+ // (5s is the timeout period that applyTransactionState waits for SF to
+ // commit the transaction)
+ EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+
+ applicationSentTime = systemTime();
+ mFlinger.setTransactionState(transactionB.states, transactionB.displays, transactionB.flags,
+ transactionB.applyToken, transactionB.inputWindowCommands,
+ transactionB.desiredPresentTime, transactionB.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks);
+
+ // this thread should have been blocked by the above transaction
+ // if this is an animation, this thread should be blocked for 5s
+ // in setTransactionState waiting for transactionA to flush. Otherwise,
+ // the transaction should be placed on the pending queue
+ if (flags & ISurfaceComposer::eAnimation) {
+ EXPECT_GE(systemTime(), applicationSentTime + s2ns(5));
+ } else {
+ EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+ }
+
+ // check that there is one binder on the pending queue.
+ auto transactionQueue = mFlinger.getTransactionQueue();
+ EXPECT_EQ(1, transactionQueue.size());
+
+ auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+ EXPECT_EQ(2, transactionStates.size());
+
+ auto& transactionStateA = transactionStates.front();
+ transactionStates.pop();
+ checkEqual(transactionA, transactionStateA);
+ auto& transactionStateB = transactionStates.front();
+ checkEqual(transactionB, transactionStateB);
+ }
+
+ bool mHasListenerCallbacks = false;
+ std::vector<ListenerCallbacks> mCallbacks;
+ int mTransactionNumber = 0;
+};
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ // called in SurfaceFlinger::signalTransaction
+ EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+ // nsecs_t time = systemTime();
+ EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
+ .WillOnce(Return(nsecs_t(5 * 1e8)))
+ .WillOnce(Return(s2ns(2)));
+ TransactionInfo transactionA; // transaction to go on pending queue
+ setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+ /*desiredPresentTime*/ s2ns(1));
+ mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+ transactionA.applyToken, transactionA.inputWindowCommands,
+ transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+ mHasListenerCallbacks, mCallbacks);
+
+ auto& transactionQueue = mFlinger.getTransactionQueue();
+ ASSERT_EQ(1, transactionQueue.size());
+
+ auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+ ASSERT_EQ(1, transactionStates.size());
+
+ auto& transactionState = transactionStates.front();
+ checkEqual(transactionA, transactionState);
+
+ // because flushing uses the cached expected present time, we send an empty
+ // transaction here (sending a null applyToken to fake it as from a
+ // different process) to re-query and reset the cached expected present time
+ TransactionInfo empty;
+ empty.applyToken = sp<IBinder>();
+ mFlinger.setTransactionState(empty.states, empty.displays, empty.flags, empty.applyToken,
+ empty.inputWindowCommands, empty.desiredPresentTime,
+ empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks);
+
+ // flush transaction queue should flush as desiredPresentTime has
+ // passed
+ mFlinger.flushTransactionQueues();
+
+ EXPECT_EQ(0, transactionQueue.size());
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
+ NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Animation) {
+ NotPlacedOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
+ NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
+ PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Animation) {
+ PlaceOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
+ PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
+ BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) {
+ BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) {
+ BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, FromHandle) {
+ sp<IBinder> badHandle;
+ auto ret = mFlinger.fromHandle(badHandle);
+ EXPECT_EQ(nullptr, ret.promote().get());
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
new file mode 100644
index 0000000..be49ef3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2019 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 "Scheduler/TimeKeeper.h"
+#include "Scheduler/Timer.h"
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+using namespace testing;
+using namespace std::literals;
+
+namespace android::scheduler {
+
+template <typename Rep, typename Per>
+constexpr nsecs_t toNs(std::chrono::duration<Rep, Per> const& tp) {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(tp).count();
+}
+
+class FixedRateIdealStubTracker : public VSyncTracker {
+public:
+ FixedRateIdealStubTracker() : mPeriod{toNs(3ms)} {}
+
+ bool addVsyncTimestamp(nsecs_t) final { return true; }
+
+ nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
+ auto const floor = timePoint % mPeriod;
+ if (floor == 0) {
+ return timePoint;
+ }
+ return timePoint - floor + mPeriod;
+ }
+
+ nsecs_t currentPeriod() const final { return mPeriod; }
+
+ void setPeriod(nsecs_t) final {}
+ void resetModel() final {}
+ void dump(std::string&) const final {}
+
+private:
+ nsecs_t const mPeriod;
+};
+
+class VRRStubTracker : public VSyncTracker {
+public:
+ VRRStubTracker(nsecs_t period) : mPeriod{period} {}
+
+ bool addVsyncTimestamp(nsecs_t) final { return true; }
+
+ nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point) const final {
+ std::lock_guard<decltype(mMutex)> lk(mMutex);
+ auto const normalized_to_base = time_point - mBase;
+ auto const floor = (normalized_to_base) % mPeriod;
+ if (floor == 0) {
+ return time_point;
+ }
+ return normalized_to_base - floor + mPeriod + mBase;
+ }
+
+ void set_interval(nsecs_t interval, nsecs_t last_known) {
+ std::lock_guard<decltype(mMutex)> lk(mMutex);
+ mPeriod = interval;
+ mBase = last_known;
+ }
+
+ nsecs_t currentPeriod() const final {
+ std::lock_guard<decltype(mMutex)> lk(mMutex);
+ return mPeriod;
+ }
+
+ void setPeriod(nsecs_t) final {}
+ void resetModel() final {}
+ void dump(std::string&) const final {}
+
+private:
+ std::mutex mutable mMutex;
+ nsecs_t mPeriod;
+ nsecs_t mBase = 0;
+};
+
+struct VSyncDispatchRealtimeTest : testing::Test {
+ static nsecs_t constexpr mDispatchGroupThreshold = toNs(100us);
+ static nsecs_t constexpr mVsyncMoveThreshold = toNs(500us);
+ static size_t constexpr mIterations = 20;
+};
+
+class RepeatingCallbackReceiver {
+public:
+ RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t wl)
+ : mWorkload(wl),
+ mCallback(
+ dispatch, [&](auto time, auto) { callback_called(time); }, "repeat0") {}
+
+ void repeatedly_schedule(size_t iterations, std::function<void(nsecs_t)> const& onEachFrame) {
+ mCallbackTimes.reserve(iterations);
+ mCallback.schedule(mWorkload, systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload);
+
+ for (auto i = 0u; i < iterations - 1; i++) {
+ std::unique_lock<decltype(mMutex)> lk(mMutex);
+ mCv.wait(lk, [&] { return mCalled; });
+ mCalled = false;
+ auto last = mLastTarget;
+ lk.unlock();
+
+ onEachFrame(last);
+
+ mCallback.schedule(mWorkload, last + mWorkload);
+ }
+
+ // wait for the last callback.
+ std::unique_lock<decltype(mMutex)> lk(mMutex);
+ mCv.wait(lk, [&] { return mCalled; });
+ }
+
+ void with_callback_times(std::function<void(std::vector<nsecs_t> const&)> const& fn) const {
+ fn(mCallbackTimes);
+ }
+
+private:
+ void callback_called(nsecs_t time) {
+ std::lock_guard<decltype(mMutex)> lk(mMutex);
+ mCallbackTimes.push_back(time);
+ mCalled = true;
+ mLastTarget = time;
+ mCv.notify_all();
+ }
+
+ nsecs_t const mWorkload;
+ VSyncCallbackRegistration mCallback;
+
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mCalled = false;
+ nsecs_t mLastTarget = 0;
+ std::vector<nsecs_t> mCallbackTimes;
+};
+
+TEST_F(VSyncDispatchRealtimeTest, triple_alarm) {
+ FixedRateIdealStubTracker tracker;
+ VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold);
+
+ static size_t constexpr num_clients = 3;
+ std::array<RepeatingCallbackReceiver, num_clients>
+ cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us)),
+ RepeatingCallbackReceiver(dispatch, toNs(0h)),
+ RepeatingCallbackReceiver(dispatch, toNs(1ms))};
+
+ auto const on_each_frame = [](nsecs_t) {};
+ std::array<std::thread, num_clients> threads{
+ std::thread([&] { cb_receiver[0].repeatedly_schedule(mIterations, on_each_frame); }),
+ std::thread([&] { cb_receiver[1].repeatedly_schedule(mIterations, on_each_frame); }),
+ std::thread([&] { cb_receiver[2].repeatedly_schedule(mIterations, on_each_frame); }),
+ };
+
+ for (auto it = threads.rbegin(); it != threads.rend(); it++) {
+ it->join();
+ }
+
+ for (auto const& cbs : cb_receiver) {
+ cbs.with_callback_times([](auto times) { EXPECT_THAT(times.size(), Eq(mIterations)); });
+ }
+}
+
+// starts at 333hz, slides down to 43hz
+TEST_F(VSyncDispatchRealtimeTest, vascillating_vrr) {
+ auto next_vsync_interval = toNs(3ms);
+ VRRStubTracker tracker(next_vsync_interval);
+ VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold);
+
+ RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+
+ auto const on_each_frame = [&](nsecs_t last_known) {
+ tracker.set_interval(next_vsync_interval += toNs(1ms), last_known);
+ };
+
+ std::thread eventThread([&] { cb_receiver.repeatedly_schedule(mIterations, on_each_frame); });
+ eventThread.join();
+
+ cb_receiver.with_callback_times([](auto times) { EXPECT_THAT(times.size(), Eq(mIterations)); });
+}
+
+// starts at 333hz, jumps to 200hz at frame 10
+TEST_F(VSyncDispatchRealtimeTest, fixed_jump) {
+ VRRStubTracker tracker(toNs(3ms));
+ VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold);
+
+ RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+
+ auto jump_frame_counter = 0u;
+ auto constexpr jump_frame_at = 10u;
+ auto const on_each_frame = [&](nsecs_t last_known) {
+ if (jump_frame_counter++ == jump_frame_at) {
+ tracker.set_interval(toNs(5ms), last_known);
+ }
+ };
+ std::thread eventThread([&] { cb_receiver.repeatedly_schedule(mIterations, on_each_frame); });
+ eventThread.join();
+
+ cb_receiver.with_callback_times([](auto times) { EXPECT_THAT(times.size(), Eq(mIterations)); });
+}
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
new file mode 100644
index 0000000..d940dc5
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -0,0 +1,925 @@
+/*
+ * Copyright 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+using namespace testing;
+using namespace std::literals;
+namespace android::scheduler {
+
+class MockVSyncTracker : public VSyncTracker {
+public:
+ MockVSyncTracker(nsecs_t period) : mPeriod{period} {
+ ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
+ .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
+ ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true));
+ }
+
+ MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
+ MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
+ MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
+ MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD0(resetModel, void());
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+
+ nsecs_t nextVSyncTime(nsecs_t timePoint) const {
+ if (timePoint % mPeriod == 0) {
+ return timePoint;
+ }
+ return (timePoint - (timePoint % mPeriod) + mPeriod);
+ }
+
+protected:
+ nsecs_t const mPeriod;
+};
+
+class ControllableClock : public TimeKeeper {
+public:
+ ControllableClock() {
+ ON_CALL(*this, alarmIn(_, _))
+ .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
+ ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
+ }
+
+ MOCK_CONST_METHOD0(now, nsecs_t());
+ MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
+ MOCK_METHOD0(alarmCancel, void());
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+
+ void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
+ mCallback = callback;
+ mNextCallbackTime = time + mCurrentTime;
+ }
+
+ nsecs_t fakeTime() const { return mCurrentTime; }
+
+ void advanceToNextCallback() {
+ mCurrentTime = mNextCallbackTime;
+ if (mCallback) {
+ mCallback();
+ }
+ }
+
+ void advanceBy(nsecs_t advancement) {
+ mCurrentTime += advancement;
+ if (mCurrentTime >= (mNextCallbackTime + mLag) && mCallback) {
+ mCallback();
+ }
+ };
+
+ void setLag(nsecs_t lag) { mLag = lag; }
+
+private:
+ std::function<void()> mCallback;
+ nsecs_t mNextCallbackTime = 0;
+ nsecs_t mCurrentTime = 0;
+ nsecs_t mLag = 0;
+};
+
+class CountingCallback {
+public:
+ CountingCallback(VSyncDispatch& dispatch)
+ : mDispatch(dispatch),
+ mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
+ std::placeholders::_1,
+ std::placeholders::_2),
+ "test")) {}
+ ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
+
+ operator VSyncDispatch::CallbackToken() const { return mToken; }
+
+ void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
+
+ VSyncDispatch& mDispatch;
+ VSyncDispatch::CallbackToken mToken;
+ std::vector<nsecs_t> mCalls;
+};
+
+class PausingCallback {
+public:
+ PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
+ : mDispatch(dispatch),
+ mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
+ std::placeholders::_1,
+ std::placeholders::_2),
+ "test")),
+ mRegistered(true),
+ mPauseAmount(pauseAmount) {}
+ ~PausingCallback() { unregister(); }
+
+ operator VSyncDispatch::CallbackToken() const { return mToken; }
+
+ void pause(nsecs_t, nsecs_t) {
+ std::unique_lock<std::mutex> lk(mMutex);
+ mPause = true;
+ mCv.notify_all();
+
+ mCv.wait_for(lk, mPauseAmount, [this] { return !mPause; });
+
+ mResourcePresent = (mResource.lock() != nullptr);
+ }
+
+ bool waitForPause() {
+ std::unique_lock<std::mutex> lk(mMutex);
+ auto waiting = mCv.wait_for(lk, 10s, [this] { return mPause; });
+ return waiting;
+ }
+
+ void stashResource(std::weak_ptr<void> const& resource) { mResource = resource; }
+
+ bool resourcePresent() { return mResourcePresent; }
+
+ void unpause() {
+ std::unique_lock<std::mutex> lk(mMutex);
+ mPause = false;
+ mCv.notify_all();
+ }
+
+ void unregister() {
+ if (mRegistered) {
+ mDispatch.unregisterCallback(mToken);
+ mRegistered = false;
+ }
+ }
+
+ VSyncDispatch& mDispatch;
+ VSyncDispatch::CallbackToken mToken;
+ bool mRegistered = true;
+
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mPause = false;
+ std::weak_ptr<void> mResource;
+ bool mResourcePresent = false;
+ std::chrono::milliseconds const mPauseAmount;
+};
+
+class VSyncDispatchTimerQueueTest : public testing::Test {
+protected:
+ std::unique_ptr<TimeKeeper> createTimeKeeper() {
+ class TimeKeeperWrapper : public TimeKeeper {
+ public:
+ TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
+ void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
+ mControllableClock.alarmIn(callback, time);
+ }
+ void alarmCancel() final { mControllableClock.alarmCancel(); }
+ nsecs_t now() const final { return mControllableClock.now(); }
+ void dump(std::string&) const final {}
+
+ private:
+ TimeKeeper& mControllableClock;
+ };
+ return std::make_unique<TimeKeeperWrapper>(mMockClock);
+ }
+
+ ~VSyncDispatchTimerQueueTest() {
+ // destructor of dispatch will cancelAlarm(). Ignore final cancel in common test.
+ Mock::VerifyAndClearExpectations(&mMockClock);
+ }
+
+ void advanceToNextCallback() { mMockClock.advanceToNextCallback(); }
+
+ NiceMock<ControllableClock> mMockClock;
+ static nsecs_t constexpr mDispatchGroupThreshold = 5;
+ nsecs_t const mPeriod = 1000;
+ nsecs_t const mVsyncMoveThreshold = 300;
+ NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
+ VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold};
+};
+
+TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmCancel());
+ {
+ VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
+ mVsyncMoveThreshold};
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
+ }
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
+ auto intended = mPeriod - 230;
+ EXPECT_CALL(mMockClock, alarmIn(_, 900));
+
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
+ EXPECT_CALL(mMockClock, alarmIn(_, 1050));
+
+ CountingCallback cb(mDispatch);
+ mDispatch.schedule(cb, 100, mPeriod);
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb.mCalls[0], Eq(1150));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) {
+ auto const now = 234;
+ mMockClock.advanceBy(234);
+ auto const workDuration = 10 * mPeriod;
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
+ .WillOnce(Return(mPeriod * 11));
+ EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
+
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmCancel());
+
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmCancel());
+
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+ mMockClock.advanceBy(950);
+ EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmCancel());
+
+ PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
+ EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+
+ std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
+ EXPECT_TRUE(cb.waitForPause());
+ EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
+ cb.unpause();
+ pausingThread.join();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmCancel());
+
+ auto resource = std::make_shared<int>(110);
+
+ PausingCallback cb(mDispatch, 50ms);
+ cb.stashResource(resource);
+ EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+
+ std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
+ EXPECT_TRUE(cb.waitForPause());
+
+ cb.unregister();
+ resource.reset();
+
+ cb.unpause();
+ pausingThread.join();
+
+ EXPECT_TRUE(cb.resourcePresent());
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+ .Times(4)
+ .WillOnce(Return(1055))
+ .WillOnce(Return(1063))
+ .WillOnce(Return(1063))
+ .WillOnce(Return(1075));
+
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+
+ mDispatch.schedule(cb0, 100, mPeriod);
+ mDispatch.schedule(cb1, 250, mPeriod);
+
+ advanceToNextCallback();
+ advanceToNextCallback();
+
+ ASSERT_THAT(cb0.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb0.mCalls[0], Eq(1075));
+ ASSERT_THAT(cb1.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb1.mCalls[0], Eq(1063));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+ .Times(4)
+ .WillOnce(Return(10000))
+ .WillOnce(Return(1000))
+ .WillOnce(Return(10000))
+ .WillOnce(Return(10000));
+
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+
+ mDispatch.schedule(cb0, 100, mPeriod * 10);
+ mDispatch.schedule(cb1, 250, mPeriod);
+ mDispatch.cancel(cb1);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+
+ mDispatch.schedule(cb0, 400, 1000);
+ mDispatch.schedule(cb1, 200, 1000);
+ mDispatch.schedule(cb1, 300, 1000);
+ advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+
+ mDispatch.schedule(cb0, 400, 1000);
+ mDispatch.schedule(cb1, 200, 1000);
+ mDispatch.schedule(cb1, 500, 1000);
+ advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
+
+ auto offset = 400;
+ auto closeOffset = offset + mDispatchGroupThreshold - 1;
+ auto notCloseOffset = offset + 2 * mDispatchGroupThreshold;
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+
+ mDispatch.schedule(cb0, 400, 1000);
+ mDispatch.schedule(cb1, 200, 1000);
+ mDispatch.schedule(cb1, closeOffset, 1000);
+
+ advanceToNextCallback();
+ ASSERT_THAT(cb0.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb0.mCalls[0], Eq(mPeriod));
+ ASSERT_THAT(cb1.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
+
+ mDispatch.schedule(cb0, 400, 2000);
+ mDispatch.schedule(cb1, notCloseOffset, 2000);
+ advanceToNextCallback();
+ ASSERT_THAT(cb1.mCalls.size(), Eq(2));
+ EXPECT_THAT(cb1.mCalls[1], Eq(2000));
+
+ advanceToNextCallback();
+ ASSERT_THAT(cb0.mCalls.size(), Eq(2));
+ EXPECT_THAT(cb0.mCalls[1], Eq(2000));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 900));
+ EXPECT_CALL(mMockClock, alarmIn(_, 800));
+ EXPECT_CALL(mMockClock, alarmIn(_, 100));
+ EXPECT_CALL(mMockClock, alarmCancel());
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+
+ mDispatch.schedule(cb0, 100, 1000);
+ mDispatch.schedule(cb1, 200, 1000);
+ advanceToNextCallback();
+ EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, setAlarmCallsAtCorrectTimeWithChangingVsync) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+ .Times(3)
+ .WillOnce(Return(950))
+ .WillOnce(Return(1975))
+ .WillOnce(Return(2950));
+
+ CountingCallback cb(mDispatch);
+ mDispatch.schedule(cb, 100, 920);
+
+ mMockClock.advanceBy(850);
+ EXPECT_THAT(cb.mCalls.size(), Eq(1));
+
+ mDispatch.schedule(cb, 100, 1900);
+ mMockClock.advanceBy(900);
+ EXPECT_THAT(cb.mCalls.size(), Eq(1));
+ mMockClock.advanceBy(125);
+ EXPECT_THAT(cb.mCalls.size(), Eq(2));
+
+ mDispatch.schedule(cb, 100, 2900);
+ mMockClock.advanceBy(975);
+ EXPECT_THAT(cb.mCalls.size(), Eq(3));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+
+ VSyncDispatch::CallbackToken tmp;
+ tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
+ "o.o");
+
+ mDispatch.schedule(tmp, 100, 1000);
+ advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) {
+ VSyncDispatch::CallbackToken tmp;
+ std::optional<nsecs_t> lastTarget;
+ tmp = mDispatch.registerCallback(
+ [&](auto timestamp, auto) {
+ EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
+ ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold),
+ ScheduleResult::Scheduled);
+ lastTarget = timestamp;
+ },
+ "oo");
+
+ mDispatch.schedule(tmp, 999, 1000);
+ advanceToNextCallback();
+ EXPECT_THAT(lastTarget, Eq(1000));
+
+ advanceToNextCallback();
+ EXPECT_THAT(lastTarget, Eq(2000));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
+
+ CountingCallback cb(mDispatch);
+ mDispatch.schedule(cb, 0, 1000);
+
+ mMockClock.advanceBy(750);
+ mDispatch.schedule(cb, 50, 1000);
+
+ advanceToNextCallback();
+ mDispatch.schedule(cb, 50, 2000);
+
+ mMockClock.advanceBy(800);
+ mDispatch.schedule(cb, 100, 2000);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+
+ mDispatch.schedule(cb0, 500, 1000);
+ mDispatch.schedule(cb1, 100, 1000);
+
+ advanceToNextCallback();
+ mDispatch.schedule(cb0, 200, 2000);
+ mDispatch.schedule(cb1, 150, 1000);
+
+ advanceToNextCallback();
+ advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+
+ CountingCallback cb0(mDispatch);
+ CountingCallback cb1(mDispatch);
+ mDispatch.schedule(cb0, 500, 1000);
+ mDispatch.schedule(cb1, 500, 20000);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
+
+ CountingCallback cb0(mDispatch);
+ mDispatch.schedule(cb0, 500, 1000);
+ mDispatch.cancel(cb0);
+ mDispatch.schedule(cb0, 100, 1000);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) {
+ VSyncDispatch::CallbackToken token(100);
+ EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error));
+ EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
+ CountingCallback cb0(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled);
+}
+
+// b/1450138150
+TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 500));
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+ mMockClock.advanceBy(400);
+
+ EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled);
+ advanceToNextCallback();
+ ASSERT_THAT(cb.mCalls.size(), Eq(1));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+ .Times(2)
+ .WillOnce(Return(1000))
+ .WillOnce(Return(1002));
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+ mMockClock.advanceBy(400);
+ EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
+ CountingCallback cb0(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+ advanceToNextCallback();
+ EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ CountingCallback cb0(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+ advanceToNextCallback();
+ EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 600));
+
+ CountingCallback cb(mDispatch);
+ EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+
+ EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled);
+
+ advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+ EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
+
+ VSyncCallbackRegistration cb(
+ mDispatch, [](auto, auto) {}, "");
+ VSyncCallbackRegistration cb1(std::move(cb));
+ cb.schedule(100, 1000);
+ cb.cancel();
+
+ cb1.schedule(500, 1000);
+ cb1.cancel();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
+ EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+ EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
+
+ VSyncCallbackRegistration cb(
+ mDispatch, [](auto, auto) {}, "");
+ VSyncCallbackRegistration cb1(
+ mDispatch, [](auto, auto) {}, "");
+ cb1 = std::move(cb);
+ cb.schedule(100, 1000);
+ cb.cancel();
+
+ cb1.schedule(500, 1000);
+ cb1.cancel();
+}
+
+// b/154303580
+TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 1200)).InSequence(seq);
+ CountingCallback cb1(mDispatch);
+ CountingCallback cb2(mDispatch);
+
+ EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(620);
+
+ EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+ mMockClock.advanceBy(80);
+
+ EXPECT_THAT(cb1.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+}
+
+// b/154303580.
+// If the same callback tries to reschedule itself after it's too late, timer opts to apply the
+// update later, as opposed to blocking the calling thread.
+TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 930)).InSequence(seq);
+ CountingCallback cb(mDispatch);
+
+ EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(620);
+
+ EXPECT_EQ(mDispatch.schedule(cb, 370, 2000), ScheduleResult::Scheduled);
+ mMockClock.advanceBy(80);
+
+ EXPECT_THAT(cb.mCalls.size(), Eq(1));
+}
+
+// b/154303580.
+TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+ CountingCallback cb1(mDispatch);
+ CountingCallback cb2(mDispatch);
+
+ EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(620);
+
+ EXPECT_EQ(mDispatch.cancel(cb2), CancelResult::Cancelled);
+
+ mMockClock.advanceBy(80);
+
+ EXPECT_THAT(cb1.mCalls.size(), Eq(1));
+ EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
+ Sequence seq;
+ EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
+ EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+ CountingCallback cb1(mDispatch);
+ CountingCallback cb2(mDispatch);
+
+ EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+ EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+ mMockClock.setLag(100);
+ mMockClock.advanceBy(620);
+
+ EXPECT_EQ(mDispatch.cancel(cb1), CancelResult::Cancelled);
+
+ EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+ EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+ mMockClock.advanceToNextCallback();
+
+ EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+ EXPECT_THAT(cb2.mCalls.size(), Eq(1));
+}
+
+class VSyncDispatchTimerQueueEntryTest : public testing::Test {
+protected:
+ nsecs_t const mPeriod = 1000;
+ nsecs_t const mVsyncMoveThreshold = 200;
+ NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
+};
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
+ std::string name("basicname");
+ VSyncDispatchTimerQueueEntry entry(
+ name, [](auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.name(), Eq(name));
+ EXPECT_FALSE(entry.lastExecutedVsyncTarget());
+ EXPECT_FALSE(entry.wakeupTime());
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+ EXPECT_FALSE(entry.wakeupTime());
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ auto const wakeup = entry.wakeupTime();
+ ASSERT_TRUE(wakeup);
+ EXPECT_THAT(*wakeup, Eq(900));
+
+ entry.disarm();
+ EXPECT_FALSE(entry.wakeupTime());
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) {
+ auto const duration = 500;
+ auto const now = 8750;
+
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration))
+ .Times(1)
+ .WillOnce(Return(10000));
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+ EXPECT_FALSE(entry.wakeupTime());
+ EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
+ auto const wakeup = entry.wakeupTime();
+ ASSERT_TRUE(wakeup);
+ EXPECT_THAT(*wakeup, Eq(9500));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
+ auto callCount = 0;
+ auto vsyncCalledTime = 0;
+ auto wakeupCalledTime = 0;
+ VSyncDispatchTimerQueueEntry entry(
+ "test",
+ [&](auto vsyncTime, auto wakeupTime) {
+ callCount++;
+ vsyncCalledTime = vsyncTime;
+ wakeupCalledTime = wakeupTime;
+ },
+ mVsyncMoveThreshold);
+
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ auto const wakeup = entry.wakeupTime();
+ ASSERT_TRUE(wakeup);
+ EXPECT_THAT(*wakeup, Eq(900));
+
+ entry.callback(entry.executing(), *wakeup);
+
+ EXPECT_THAT(callCount, Eq(1));
+ EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
+ EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
+ EXPECT_FALSE(entry.wakeupTime());
+ auto lastCalledTarget = entry.lastExecutedVsyncTarget();
+ ASSERT_TRUE(lastCalledTarget);
+ EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) {
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+ .Times(2)
+ .WillOnce(Return(1000))
+ .WillOnce(Return(1020));
+
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+ EXPECT_FALSE(entry.wakeupTime());
+ entry.update(mStubTracker, 0);
+ EXPECT_FALSE(entry.wakeupTime());
+
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ auto wakeup = entry.wakeupTime();
+ ASSERT_TRUE(wakeup);
+ EXPECT_THAT(wakeup, Eq(900));
+
+ entry.update(mStubTracker, 0);
+ wakeup = entry.wakeupTime();
+ ASSERT_TRUE(wakeup);
+ EXPECT_THAT(*wakeup, Eq(920));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ entry.update(mStubTracker, 0);
+
+ auto const wakeup = entry.wakeupTime();
+ ASSERT_TRUE(wakeup);
+ EXPECT_THAT(*wakeup, Eq(wakeup));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ entry.executing(); // 1000 is executing
+ // had 1000 not been executing, this could have been scheduled for time 800.
+ EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+
+ EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
+
+ EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest,
+ willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+ Sequence seq;
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
+ .InSequence(seq)
+ .WillOnce(Return(1000));
+ EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold))
+ .InSequence(seq)
+ .WillOnce(Return(2000));
+
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+
+ entry.executing(); // 1000 is executing
+
+ EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+ EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) {
+ static constexpr auto effectualOffset = 200;
+ VSyncDispatchTimerQueueEntry entry(
+ "test", [](auto, auto) {}, mVsyncMoveThreshold);
+ EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
+ entry.addPendingWorkloadUpdate(100, 400);
+ entry.addPendingWorkloadUpdate(effectualOffset, 700);
+ EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
+ entry.update(mStubTracker, 0);
+ EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
+ EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
+}
+
+} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
new file mode 100644
index 0000000..9c1ec07
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2020 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/VSyncModulator.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+
+namespace android::scheduler {
+
+class MockScheduler : public IPhaseOffsetControl {
+public:
+ void setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
+ mPhaseOffset[handle] = phaseOffset;
+ }
+
+ nsecs_t getOffset(ConnectionHandle handle) { return mPhaseOffset[handle]; }
+
+private:
+ std::unordered_map<ConnectionHandle, nsecs_t> mPhaseOffset;
+};
+
+class VSyncModulatorTest : public testing::Test {
+protected:
+ static constexpr auto MIN_EARLY_FRAME_COUNT_TRANSACTION =
+ VSyncModulator::MIN_EARLY_FRAME_COUNT_TRANSACTION;
+ // Add a 1ms slack to avoid strange timer race conditions.
+ static constexpr auto MARGIN_FOR_TX_APPLY = VSyncModulator::MARGIN_FOR_TX_APPLY + 1ms;
+
+ // Used to enumerate the different offsets we have
+ enum {
+ SF_LATE,
+ APP_LATE,
+ SF_EARLY,
+ APP_EARLY,
+ SF_EARLY_GL,
+ APP_EARLY_GL,
+ };
+
+ std::unique_ptr<VSyncModulator> mVSyncModulator;
+ MockScheduler mMockScheduler;
+ ConnectionHandle mAppConnection{1};
+ ConnectionHandle mSfConnection{2};
+ VSyncModulator::OffsetsConfig mOffsets = {{SF_EARLY, APP_EARLY},
+ {SF_EARLY_GL, APP_EARLY_GL},
+ {SF_LATE, APP_LATE}};
+
+ void SetUp() override {
+ mVSyncModulator = std::make_unique<VSyncModulator>(mMockScheduler, mAppConnection,
+ mSfConnection, mOffsets);
+ mVSyncModulator->setPhaseOffsets(mOffsets);
+
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+ };
+
+ void TearDown() override { mVSyncModulator.reset(); }
+};
+
+TEST_F(VSyncModulatorTest, Normal) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+ }
+}
+
+TEST_F(VSyncModulatorTest, EarlyEnd) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStart) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithEarly) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Early);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithMoreTransactions) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEnd) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+ std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+ mVSyncModulator->onTransactionHandled();
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+ for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+ }
+
+ mVSyncModulator->onRefreshed(false);
+ EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+ EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
new file mode 100644
index 0000000..fc39235
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2019 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/VSyncPredictor.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <algorithm>
+#include <chrono>
+#include <utility>
+
+using namespace testing;
+using namespace std::literals;
+
+namespace android::scheduler {
+
+MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") {
+ return arg <= value + tolerance && arg >= value - tolerance;
+}
+
+std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) {
+ std::vector<nsecs_t> vsyncs(count);
+ std::generate(vsyncs.begin(), vsyncs.end(),
+ [&, n = 0]() mutable { return n++ * period + bias; });
+ return vsyncs;
+}
+
+struct VSyncPredictorTest : testing::Test {
+ nsecs_t mNow = 0;
+ nsecs_t mPeriod = 1000;
+ static constexpr size_t kHistorySize = 10;
+ static constexpr size_t kMinimumSamplesForPrediction = 6;
+ static constexpr size_t kOutlierTolerancePercent = 25;
+ static constexpr nsecs_t mMaxRoundingError = 100;
+
+ VSyncPredictor tracker{mPeriod, kHistorySize, kMinimumSamplesForPrediction,
+ kOutlierTolerancePercent};
+};
+
+TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) {
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+
+ EXPECT_THAT(slope, Eq(mPeriod));
+ EXPECT_THAT(intercept, Eq(0));
+
+ auto const changedPeriod = 2000;
+ tracker.setPeriod(changedPeriod);
+ std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, Eq(changedPeriod));
+ EXPECT_THAT(intercept, Eq(0));
+}
+
+TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) {
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ EXPECT_TRUE(tracker.needsMoreSamples(mNow += mPeriod));
+ tracker.addVsyncTimestamp(mNow);
+ }
+ EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+}
+
+TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) {
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ tracker.addVsyncTimestamp(mNow += mPeriod);
+ }
+ EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+
+ auto const changedPeriod = mPeriod * 2;
+ tracker.setPeriod(changedPeriod);
+ EXPECT_TRUE(tracker.needsMoreSamples(mNow));
+
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ EXPECT_TRUE(tracker.needsMoreSamples(mNow += changedPeriod));
+ tracker.addVsyncTimestamp(mNow);
+ }
+ EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+}
+
+TEST_F(VSyncPredictorTest, transitionsToModelledPointsAfterSynthetic) {
+ auto last = mNow;
+ auto const bias = 10;
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
+ mNow += mPeriod - bias;
+ last = mNow;
+ tracker.addVsyncTimestamp(mNow);
+ mNow += bias;
+ }
+
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
+}
+
+TEST_F(VSyncPredictorTest, uponNotifiedOfInaccuracyUsesSynthetic) {
+ auto const slightlyLessPeriod = mPeriod - 10;
+ auto const changedPeriod = mPeriod - 1;
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ tracker.addVsyncTimestamp(mNow += slightlyLessPeriod);
+ }
+
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyLessPeriod));
+ tracker.setPeriod(changedPeriod);
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + changedPeriod));
+}
+
+// b/159882858
+TEST_F(VSyncPredictorTest, updatesTimebaseForSyntheticAfterIdleTime) {
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
+ }
+
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+
+ auto const halfPeriod = mPeriod >> 2;
+ nsecs_t relativelyLongGapWithDrift = mPeriod * 100 + halfPeriod;
+
+ EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += relativelyLongGapWithDrift));
+
+ tracker.resetModel();
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+}
+
+TEST_F(VSyncPredictorTest, uponBadVsyncWillSwitchToSyntheticWhileRecalibrating) {
+ auto const slightlyMorePeriod = mPeriod + 10;
+ for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+ EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += slightlyMorePeriod));
+ }
+
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyMorePeriod));
+
+ auto const halfPeriod = mPeriod >> 2;
+ EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += halfPeriod));
+
+ tracker.resetModel();
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+}
+
+TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_60hzHighVariance) {
+ // these are precomputed simulated 16.6s vsyncs with uniform distribution +/- 1.6ms error
+ std::vector<nsecs_t> const simulatedVsyncs{
+ 15492949, 32325658, 49534984, 67496129, 84652891,
+ 100332564, 117737004, 132125931, 149291099, 165199602,
+ };
+ auto constexpr idealPeriod = 16600000;
+ auto constexpr expectedPeriod = 16639242;
+ auto constexpr expectedIntercept = 1049341;
+
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_90hzLowVariance) {
+ // these are precomputed simulated 11.1 vsyncs with uniform distribution +/- 1ms error
+ std::vector<nsecs_t> const simulatedVsyncs{
+ 11167047, 22603464, 32538479, 44938134, 56321268,
+ 66730346, 78062637, 88171429, 99707843, 111397621,
+ };
+ auto idealPeriod = 11110000;
+ auto expectedPeriod = 11089413;
+ auto expectedIntercept = 94421;
+
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, adaptsToFenceTimelinesDiscontinuous_22hzLowVariance) {
+ // these are 11.1s vsyncs with low variance, randomly computed, between -1 and 1ms
+ std::vector<nsecs_t> const simulatedVsyncs{
+ 45259463, // 0
+ 91511026, // 1
+ 136307650, // 2
+ 1864501714, // 40
+ 1908641034, // 41
+ 1955278544, // 42
+ 4590180096, // 100
+ 4681594994, // 102
+ 5499224734, // 120
+ 5591378272, // 122
+ };
+ auto idealPeriod = 45454545;
+ auto expectedPeriod = 45450152;
+ auto expectedIntercept = 469647;
+
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) {
+ std::vector<nsecs_t> const simulatedVsyncs{
+ 1992548, // 0
+ 4078038, // 1
+ 6165794, // 2
+ 7958171, // 3
+ 10193537, // 4
+ 2401840200, // 1200
+ 2403000000, // an outlier that should be excluded (1201 and a half)
+ 2405803629, // 1202
+ 2408028599, // 1203
+ 2410121051, // 1204
+ };
+ auto idealPeriod = 2000000;
+ auto expectedPeriod = 1999892;
+ auto expectedIntercept = 86342;
+
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, handlesVsyncChange) {
+ auto const fastPeriod = 100;
+ auto const fastTimeBase = 100;
+ auto const slowPeriod = 400;
+ auto const slowTimeBase = 800;
+ auto const simulatedVsyncsFast =
+ generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
+ auto const simulatedVsyncsSlow =
+ generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
+
+ tracker.setPeriod(fastPeriod);
+ for (auto const& timestamp : simulatedVsyncsFast) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+
+ auto const mMaxRoundingError = 100;
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(fastPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(0, mMaxRoundingError));
+
+ tracker.setPeriod(slowPeriod);
+ for (auto const& timestamp : simulatedVsyncsSlow) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+ std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(slowPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(0, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) {
+ auto const fastPeriod = 101000;
+ auto const fastTimeBase = fastPeriod - 500;
+ auto const fastPeriod2 = 99000;
+
+ auto const slowPeriod = 400000;
+ auto const slowTimeBase = 800000 - 201;
+ auto const simulatedVsyncsFast =
+ generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
+ auto const simulatedVsyncsSlow =
+ generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
+ auto const simulatedVsyncsFast2 =
+ generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod2, fastTimeBase);
+
+ auto idealPeriod = 100000;
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncsFast) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, Eq(fastPeriod));
+ EXPECT_THAT(intercept, Eq(0));
+
+ tracker.setPeriod(slowPeriod);
+ for (auto const& timestamp : simulatedVsyncsSlow) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+
+ // we had a model for 100ns mPeriod before, use that until the new samples are
+ // sufficiently built up
+ tracker.setPeriod(idealPeriod);
+ std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, Eq(fastPeriod));
+ EXPECT_THAT(intercept, Eq(0));
+
+ for (auto const& timestamp : simulatedVsyncsFast2) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+ std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, Eq(fastPeriod2));
+ EXPECT_THAT(intercept, Eq(0));
+}
+
+TEST_F(VSyncPredictorTest, willBecomeInaccurateAfterA_longTimeWithNoSamples) {
+ auto const simulatedVsyncs = generateVsyncTimestamps(kMinimumSamplesForPrediction, mPeriod, 0);
+
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+ auto const mNow = *simulatedVsyncs.rbegin();
+ EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+
+ // TODO: would be better to decay this as a result of the variance of the samples
+ static auto constexpr aLongTimeOut = 1000000000;
+ EXPECT_TRUE(tracker.needsMoreSamples(mNow + aLongTimeOut));
+}
+
+TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) {
+ auto const simulatedVsyncs =
+ generateVsyncTimestamps(kMinimumSamplesForPrediction + 1, mPeriod, 0);
+ nsecs_t const mNow = 0;
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mPeriod));
+
+ nsecs_t const aBitOfTime = 422;
+
+ for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+ tracker.addVsyncTimestamp(simulatedVsyncs[i]);
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
+ Eq(mPeriod + simulatedVsyncs[i]));
+ }
+
+ for (auto i = kMinimumSamplesForPrediction; i < simulatedVsyncs.size(); i++) {
+ tracker.addVsyncTimestamp(simulatedVsyncs[i]);
+ EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
+ Eq(mPeriod + simulatedVsyncs[i]));
+ }
+}
+
+// See b/145667109, and comment in prod code under test.
+TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
+ std::vector<nsecs_t> const simulatedVsyncs{
+ 158929578733000,
+ 158929306806205, // oldest TS in ringbuffer
+ 158929650879052,
+ 158929661969209,
+ 158929684198847,
+ 158929695268171,
+ 158929706370359,
+ };
+ auto const idealPeriod = 11111111;
+ auto const expectedPeriod = 11113919;
+ auto const expectedIntercept = -1195945;
+
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+
+ // (timePoint - oldestTS) % expectedPeriod works out to be: 395334
+ // (timePoint - oldestTS) / expectedPeriod works out to be: 38.96
+ // so failure to account for the offset will floor the ordinal to 38, which was in the past.
+ auto const timePoint = 158929728723871;
+ auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
+ EXPECT_THAT(prediction, Ge(timePoint));
+}
+
+// See b/151146131
+TEST_F(VSyncPredictorTest, hasEnoughPrecision) {
+ VSyncPredictor tracker{mPeriod, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent};
+ std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675,
+ 840923581635, 840940161584, 840956868096,
+ 840973702473, 840990256277, 841007116851,
+ 841023722530, 841040452167, 841057073002,
+ 841073800920, 841090474360, 841107278632,
+ 841123898634, 841140750875, 841157287127,
+ 841591357014, 840856664232
+
+ };
+ auto const idealPeriod = 16666666;
+ auto const expectedPeriod = 16698426;
+ auto const expectedIntercept = 58055;
+
+ tracker.setPeriod(idealPeriod);
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
+ auto const idealPeriod = 10000;
+ auto const realPeriod = 10500;
+ tracker.setPeriod(idealPeriod);
+ for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+ tracker.addVsyncTimestamp(i * realPeriod);
+ }
+
+ EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+ IsCloseTo(realPeriod, mMaxRoundingError));
+ tracker.resetModel();
+ EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+ IsCloseTo(idealPeriod, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
+ constexpr auto kNumVsyncs = 100;
+ auto invalidPeriod = mPeriod;
+ auto now = 0;
+ for (int i = 0; i < kNumVsyncs; i++) {
+ tracker.addVsyncTimestamp(now);
+ now += invalidPeriod;
+ invalidPeriod *= 0.9f;
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
+
+ // When VsyncPredictor returns the period it means that it doesn't know how to predict and
+ // it needs to get more samples
+ if (slope == mPeriod && intercept == 0) {
+ EXPECT_TRUE(tracker.needsMoreSamples(now));
+ }
+ }
+}
+
+constexpr nsecs_t operator""_years(unsigned long long years) noexcept {
+ using namespace std::chrono_literals;
+ return years * 365 * 24 * 3600 *
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+}
+TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) {
+ constexpr nsecs_t timeBase = 100_years;
+
+ for (auto i = 0; i < kHistorySize; i++) {
+ tracker.addVsyncTimestamp(timeBase + i * mPeriod);
+ }
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(mPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, Eq(0));
+}
+
+} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
new file mode 100644
index 0000000..a972562
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -0,0 +1,742 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/VSyncDispatch.h"
+#include "Scheduler/VSyncReactor.h"
+#include "Scheduler/VSyncTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/Fence.h>
+#include <ui/FenceTime.h>
+#include <array>
+
+using namespace testing;
+using namespace std::literals;
+namespace android::scheduler {
+
+class MockVSyncTracker : public VSyncTracker {
+public:
+ MockVSyncTracker() { ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); }
+ MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
+ MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
+ MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
+ MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD0(resetModel, void());
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+class VSyncTrackerWrapper : public VSyncTracker {
+public:
+ VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {}
+
+ bool addVsyncTimestamp(nsecs_t timestamp) final {
+ return mTracker->addVsyncTimestamp(timestamp);
+ }
+ nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
+ return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
+ }
+ nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
+ void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
+ void resetModel() final { mTracker->resetModel(); }
+ void dump(std::string& result) const final { mTracker->dump(result); }
+
+private:
+ std::shared_ptr<VSyncTracker> const mTracker;
+};
+
+class MockClock : public Clock {
+public:
+ MOCK_CONST_METHOD0(now, nsecs_t());
+};
+
+class ClockWrapper : public Clock {
+public:
+ ClockWrapper(std::shared_ptr<Clock> const& clock) : mClock(clock) {}
+
+ nsecs_t now() const { return mClock->now(); }
+
+private:
+ std::shared_ptr<Clock> const mClock;
+};
+
+class MockVSyncDispatch : public VSyncDispatch {
+public:
+ MOCK_METHOD2(registerCallback,
+ CallbackToken(std::function<void(nsecs_t, nsecs_t)> const&, std::string));
+ MOCK_METHOD1(unregisterCallback, void(CallbackToken));
+ MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
+ MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
+ MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+class VSyncDispatchWrapper : public VSyncDispatch {
+public:
+ VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {}
+ CallbackToken registerCallback(std::function<void(nsecs_t, nsecs_t)> const& callbackFn,
+ std::string callbackName) final {
+ return mDispatch->registerCallback(callbackFn, callbackName);
+ }
+
+ void unregisterCallback(CallbackToken token) final { mDispatch->unregisterCallback(token); }
+
+ ScheduleResult schedule(CallbackToken token, nsecs_t workDuration,
+ nsecs_t earliestVsync) final {
+ return mDispatch->schedule(token, workDuration, earliestVsync);
+ }
+
+ CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); }
+
+ void dump(std::string& result) const final { return mDispatch->dump(result); }
+
+private:
+ std::shared_ptr<VSyncDispatch> const mDispatch;
+};
+
+std::shared_ptr<FenceTime> generateInvalidFence() {
+ sp<Fence> fence = new Fence();
+ return std::make_shared<FenceTime>(fence);
+}
+
+std::shared_ptr<FenceTime> generatePendingFence() {
+ sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+ return std::make_shared<FenceTime>(fence);
+}
+
+void signalFenceWithTime(std::shared_ptr<FenceTime> const& fence, nsecs_t time) {
+ FenceTime::Snapshot snap(time);
+ fence->applyTrustedSnapshot(snap);
+}
+
+std::shared_ptr<FenceTime> generateSignalledFenceWithTime(nsecs_t time) {
+ sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+ std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
+ signalFenceWithTime(ft, time);
+ return ft;
+}
+
+class StubCallback : public DispSync::Callback {
+public:
+ void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
+ std::lock_guard<std::mutex> lk(mMutex);
+ mLastCallTime = when;
+ }
+ std::optional<nsecs_t> lastCallTime() const {
+ std::lock_guard<std::mutex> lk(mMutex);
+ return mLastCallTime;
+ }
+
+private:
+ std::mutex mutable mMutex;
+ std::optional<nsecs_t> mLastCallTime GUARDED_BY(mMutex);
+};
+
+class VSyncReactorTest : public testing::Test {
+protected:
+ VSyncReactorTest()
+ : mMockDispatch(std::make_shared<NiceMock<MockVSyncDispatch>>()),
+ mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
+ mMockClock(std::make_shared<NiceMock<MockClock>>()),
+ mReactor(std::make_unique<ClockWrapper>(mMockClock),
+ std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
+ std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit,
+ false /* supportKernelIdleTimer */) {
+ ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow));
+ ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period));
+ }
+
+ std::shared_ptr<MockVSyncDispatch> mMockDispatch;
+ std::shared_ptr<MockVSyncTracker> mMockTracker;
+ std::shared_ptr<MockClock> mMockClock;
+ static constexpr size_t kPendingLimit = 3;
+ static constexpr nsecs_t mDummyTime = 47;
+ static constexpr nsecs_t mPhase = 3000;
+ static constexpr nsecs_t mAnotherPhase = 5200;
+ static constexpr nsecs_t period = 10000;
+ static constexpr nsecs_t mFakeVSyncTime = 2093;
+ static constexpr nsecs_t mFakeWakeupTime = 1892;
+ static constexpr nsecs_t mFakeNow = 2214;
+ static constexpr const char mName[] = "callbacky";
+ VSyncDispatch::CallbackToken const mFakeToken{2398};
+
+ nsecs_t lastCallbackTime = 0;
+ StubCallback outerCb;
+ std::function<void(nsecs_t, nsecs_t)> innerCb;
+
+ VSyncReactor mReactor;
+};
+
+TEST_F(VSyncReactorTest, addingNullFenceCheck) {
+ EXPECT_FALSE(mReactor.addPresentFence(nullptr));
+}
+
+TEST_F(VSyncReactorTest, addingInvalidFenceSignalsNeedsMoreInfo) {
+ EXPECT_TRUE(mReactor.addPresentFence(generateInvalidFence()));
+}
+
+TEST_F(VSyncReactorTest, addingSignalledFenceAddsToTracker) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime));
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)));
+}
+
+TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) {
+ nsecs_t anotherDummyTime = 2919019201;
+
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(0);
+ auto pendingFence = generatePendingFence();
+ EXPECT_FALSE(mReactor.addPresentFence(pendingFence));
+ Mock::VerifyAndClearExpectations(mMockTracker.get());
+
+ signalFenceWithTime(pendingFence, mDummyTime);
+
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime));
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(anotherDummyTime));
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(anotherDummyTime)));
+}
+
+TEST_F(VSyncReactorTest, limitsPendingFences) {
+ std::array<std::shared_ptr<FenceTime>, kPendingLimit * 2> fences;
+ std::array<nsecs_t, fences.size()> fakeTimes;
+ std::generate(fences.begin(), fences.end(), [] { return generatePendingFence(); });
+ std::generate(fakeTimes.begin(), fakeTimes.end(), [i = 10]() mutable {
+ i++;
+ return i * i;
+ });
+
+ for (auto const& fence : fences) {
+ mReactor.addPresentFence(fence);
+ }
+
+ for (auto i = fences.size() - kPendingLimit; i < fences.size(); i++) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimes[i]));
+ }
+
+ for (auto i = 0u; i < fences.size(); i++) {
+ signalFenceWithTime(fences[i], fakeTimes[i]);
+ }
+ mReactor.addPresentFence(generatePendingFence());
+}
+
+TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) {
+ static constexpr size_t aFewTimes = 8;
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime)).Times(1);
+
+ mReactor.setIgnorePresentFences(true);
+ for (auto i = 0; i < aFewTimes; i++) {
+ mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime));
+ }
+
+ mReactor.setIgnorePresentFences(false);
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)));
+}
+
+TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) {
+ bool periodFlushed = true;
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2);
+ mReactor.setIgnorePresentFences(true);
+
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+
+ EXPECT_TRUE(mReactor.addResyncSample(0, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(newPeriod, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshNow) {
+ nsecs_t const fakeTimestamp = 4839;
+ EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0);
+ EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(_))
+ .Times(1)
+ .WillOnce(Return(fakeTimestamp));
+
+ EXPECT_THAT(mReactor.computeNextRefresh(0, mMockClock->now()), Eq(fakeTimestamp));
+}
+
+TEST_F(VSyncReactorTest, queriesTrackerForExpectedPresentTime) {
+ nsecs_t const fakeTimestamp = 4839;
+ EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0);
+ EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(_))
+ .Times(1)
+ .WillOnce(Return(fakeTimestamp));
+
+ EXPECT_THAT(mReactor.expectedPresentTime(mMockClock->now()), Eq(fakeTimestamp));
+}
+
+TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshFuture) {
+ nsecs_t const fakeTimestamp = 4839;
+ nsecs_t const fakePeriod = 1010;
+ nsecs_t const mFakeNow = 2214;
+ int const numPeriodsOut = 3;
+ EXPECT_CALL(*mMockClock, now()).WillOnce(Return(mFakeNow));
+ EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod));
+ EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(mFakeNow + numPeriodsOut * fakePeriod))
+ .WillOnce(Return(fakeTimestamp));
+ EXPECT_THAT(mReactor.computeNextRefresh(numPeriodsOut, mMockClock->now()), Eq(fakeTimestamp));
+}
+
+TEST_F(VSyncReactorTest, getPeriod) {
+ nsecs_t const fakePeriod = 1010;
+ EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod));
+ EXPECT_THAT(mReactor.getPeriod(), Eq(fakePeriod));
+}
+
+TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) {
+ nsecs_t const newPeriod = 5000;
+ EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
+ mReactor.setPeriod(newPeriod);
+
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addResyncSample(20000, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ Mock::VerifyAndClearExpectations(mMockTracker.get());
+ EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
+
+ EXPECT_FALSE(mReactor.addResyncSample(25000, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) {
+ nsecs_t sampleTime = 0;
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+
+ mReactor.setPeriod(period);
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) {
+ nsecs_t sampleTime = 0;
+ nsecs_t const secondPeriod = 5000;
+ nsecs_t const thirdPeriod = 2000;
+
+ mReactor.setPeriod(secondPeriod);
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ mReactor.setPeriod(thirdPeriod);
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSync) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_))
+ .WillOnce(Return(false))
+ .WillOnce(Return(true))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+
+ nsecs_t skewyPeriod = period >> 1;
+ bool periodFlushed = false;
+ nsecs_t sampleTime = 0;
+ EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSyncPendingFence) {
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_))
+ .Times(2)
+ .WillOnce(Return(false))
+ .WillOnce(Return(true));
+
+ auto fence = generatePendingFence();
+ EXPECT_FALSE(mReactor.addPresentFence(fence));
+ signalFenceWithTime(fence, period >> 1);
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) {
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) {
+ nsecs_t const newPeriod = 5000;
+ EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
+ mReactor.setPeriod(newPeriod);
+
+ bool periodFlushed = true;
+ EXPECT_TRUE(mReactor.addResyncSample(5000, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ Mock::VerifyAndClearExpectations(mMockTracker.get());
+
+ EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
+ EXPECT_FALSE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, addResyncSampleTypical) {
+ nsecs_t const fakeTimestamp = 3032;
+ bool periodFlushed = false;
+
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimestamp));
+ EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, addResyncSamplePeriodChanges) {
+ bool periodFlushed = false;
+ nsecs_t const newPeriod = 4000;
+
+ mReactor.setPeriod(newPeriod);
+
+ auto time = 0;
+ auto constexpr numTimestampSubmissions = 10;
+ for (auto i = 0; i < numTimestampSubmissions; i++) {
+ time += period;
+ EXPECT_TRUE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ }
+
+ time += newPeriod;
+ EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+
+ for (auto i = 0; i < numTimestampSubmissions; i++) {
+ time += newPeriod;
+ EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ }
+}
+
+TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsHwVsync) {
+ auto time = 0;
+ bool periodFlushed = false;
+ nsecs_t const newPeriod = 4000;
+ mReactor.setPeriod(newPeriod);
+
+ time += period;
+ mReactor.addResyncSample(time, std::nullopt, &periodFlushed);
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+
+ time += newPeriod;
+ mReactor.addResyncSample(time, std::nullopt, &periodFlushed);
+
+ EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
+ return period - phase;
+}
+
+TEST_F(VSyncReactorTest, addEventListener) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, addEventListenerTwiceChangesPhase) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) // mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, eventListenerGetsACallbackAndReschedules) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
+ .Times(2)
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ ASSERT_TRUE(innerCb);
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
+}
+
+TEST_F(VSyncReactorTest, callbackTimestampDistributedIsWakeupTime) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, _))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
+ .InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ ASSERT_TRUE(innerCb);
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
+ EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeWakeupTime));
+}
+
+TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+}
+
+// b/149221293
+TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) {
+ class SelfRemovingCallback : public DispSync::Callback {
+ public:
+ SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {}
+ void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
+ mVsr.removeEventListener(this, &when);
+ }
+
+ private:
+ VSyncReactor& mVsr;
+ } selfRemover(mReactor);
+
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &selfRemover, lastCallbackTime);
+ innerCb(0, 0);
+}
+
+TEST_F(VSyncReactorTest, addEventListenerChangePeriod) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, mAnotherPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+ EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, changingPeriodChangesOffsetsOnNextCb) {
+ static constexpr nsecs_t anotherPeriod = 23333;
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+ .InSequence(seq);
+ EXPECT_CALL(*mMockTracker, setPeriod(anotherPeriod));
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(anotherPeriod, mPhase), mFakeNow))
+ .InSequence(seq);
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+
+ bool periodFlushed = false;
+ mReactor.setPeriod(anotherPeriod);
+ EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, std::nullopt, &periodFlushed));
+ EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, std::nullopt, &periodFlushed));
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, offsetsAppliedOnNextOpportunity) {
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), _))
+ .InSequence(seq)
+ .WillOnce(Return(ScheduleResult::Scheduled));
+
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
+ .InSequence(seq)
+ .WillOnce(Return(ScheduleResult::Scheduled));
+
+ EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
+ .InSequence(seq)
+ .WillOnce(Return(ScheduleResult::Scheduled));
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.changePhaseOffset(&outerCb, mAnotherPhase);
+ ASSERT_TRUE(innerCb);
+ innerCb(mFakeVSyncTime, mFakeWakeupTime);
+}
+
+TEST_F(VSyncReactorTest, negativeOffsetsApplied) {
+ nsecs_t const negativePhase = -4000;
+ Sequence seq;
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .InSequence(seq)
+ .WillOnce(Return(mFakeToken));
+ EXPECT_CALL(*mMockDispatch,
+ schedule(mFakeToken, computeWorkload(period, negativePhase), mFakeNow))
+ .InSequence(seq);
+ mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, beginResyncResetsModel) {
+ EXPECT_CALL(*mMockTracker, resetModel());
+ mReactor.beginResync();
+}
+
+TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) {
+ bool periodFlushed = true;
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(3);
+ mReactor.setIgnorePresentFences(true);
+
+ nsecs_t const newPeriod = 5000;
+ mReactor.setPeriod(newPeriod);
+
+ EXPECT_TRUE(mReactor.addResyncSample(0, 0, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_TRUE(mReactor.addResyncSample(newPeriod, 0, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ EXPECT_FALSE(mReactor.addResyncSample(newPeriod, newPeriod, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+
+ EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) {
+ // Create a reactor which supports the kernel idle timer
+ auto idleReactor = VSyncReactor(std::make_unique<ClockWrapper>(mMockClock),
+ std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
+ std::make_unique<VSyncTrackerWrapper>(mMockTracker),
+ kPendingLimit, true /* supportKernelIdleTimer */);
+
+ bool periodFlushed = true;
+ EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(5);
+ idleReactor.setIgnorePresentFences(true);
+
+ // First, set the same period, which should only be confirmed when we receive two
+ // matching callbacks
+ idleReactor.setPeriod(10000);
+ EXPECT_TRUE(idleReactor.addResyncSample(0, 0, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ // Correct period but incorrect timestamp delta
+ EXPECT_TRUE(idleReactor.addResyncSample(0, 10000, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ // Correct period and correct timestamp delta
+ EXPECT_FALSE(idleReactor.addResyncSample(10000, 10000, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+
+ // Then, set a new period, which should be confirmed as soon as we receive a callback
+ // reporting the new period
+ nsecs_t const newPeriod = 5000;
+ idleReactor.setPeriod(newPeriod);
+ // Incorrect timestamp delta and period
+ EXPECT_TRUE(idleReactor.addResyncSample(20000, 10000, &periodFlushed));
+ EXPECT_FALSE(periodFlushed);
+ // Incorrect timestamp delta but correct period
+ EXPECT_FALSE(idleReactor.addResyncSample(20000, 5000, &periodFlushed));
+ EXPECT_TRUE(periodFlushed);
+
+ EXPECT_TRUE(idleReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+using VSyncReactorDeathTest = VSyncReactorTest;
+TEST_F(VSyncReactorDeathTest, invalidRemoval) {
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+ EXPECT_DEATH(mReactor.removeEventListener(&outerCb, &lastCallbackTime), ".*");
+}
+
+TEST_F(VSyncReactorDeathTest, invalidChange) {
+ EXPECT_DEATH(mReactor.changePhaseOffset(&outerCb, mPhase), ".*");
+
+ // the current DispSync-interface usage pattern has evolved around an implementation quirk,
+ // which is a callback is assumed to always exist, and it is valid api usage to change the
+ // offset of an object that is in the removed state.
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+ mReactor.changePhaseOffset(&outerCb, mPhase);
+}
+
+TEST_F(VSyncReactorDeathTest, cannotScheduleOnRegistration) {
+ ON_CALL(*mMockDispatch, schedule(_, _, _))
+ .WillByDefault(Return(ScheduleResult::CannotSchedule));
+ EXPECT_DEATH(mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime), ".*");
+}
+
+TEST_F(VSyncReactorDeathTest, cannotScheduleOnCallback) {
+ EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+ .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+ EXPECT_CALL(*mMockDispatch, schedule(_, _, _)).WillOnce(Return(ScheduleResult::Scheduled));
+
+ mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+ ASSERT_TRUE(innerCb);
+ Mock::VerifyAndClearExpectations(mMockDispatch.get());
+
+ ON_CALL(*mMockDispatch, schedule(_, _, _))
+ .WillByDefault(Return(ScheduleResult::CannotSchedule));
+ EXPECT_DEATH(innerCb(mFakeVSyncTime, mFakeWakeupTime), ".*");
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
index 7ed57b9..0780af1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "mock/DisplayHardware/MockComposer.h"
namespace android {
@@ -27,3 +31,6 @@
} // namespace mock
} // namespace Hwc2
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 3c7e1da..c2c5072 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -39,12 +39,13 @@
using android::hardware::graphics::composer::V2_1::Display;
using android::hardware::graphics::composer::V2_1::Error;
using android::hardware::graphics::composer::V2_1::IComposer;
-using android::hardware::graphics::composer::V2_1::IComposerCallback;
using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_3::IComposerClient;
+using android::hardware::graphics::composer::V2_4::IComposerCallback;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
class Composer : public Hwc2::Composer {
public:
+ using Display = android::hardware::graphics::composer::V2_1::Display;
Composer();
~Composer() override;
@@ -71,7 +72,6 @@
MOCK_METHOD2(getDisplayName, Error(Display, std::string*));
MOCK_METHOD4(getDisplayRequests,
Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*));
- MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
MOCK_METHOD1(getPerFrameMetadataKeys,
@@ -118,10 +118,29 @@
MOCK_METHOD4(setDisplayContentSamplingEnabled, Error(Display, bool, uint8_t, uint64_t));
MOCK_METHOD4(getDisplayedContentSample,
Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
- MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
+ MOCK_METHOD0(isVsyncPeriodSwitchSupported, bool());
+ MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
+ MOCK_METHOD2(getDisplayConnectionType,
+ V2_4::Error(Display, IComposerClient::DisplayConnectionType*));
+ MOCK_METHOD3(getSupportedDisplayVsyncPeriods,
+ V2_4::Error(Display, Config, std::vector<VsyncPeriodNanos>*));
+ MOCK_METHOD2(getDisplayVsyncPeriod, V2_4::Error(Display, VsyncPeriodNanos*));
+ MOCK_METHOD4(setActiveConfigWithConstraints,
+ V2_4::Error(Display, Config, const IComposerClient::VsyncPeriodChangeConstraints&,
+ VsyncPeriodChangeTimeline*));
+ MOCK_METHOD2(setAutoLowLatencyMode, V2_4::Error(Display, bool));
+ MOCK_METHOD2(getSupportedContentTypes,
+ V2_4::Error(Display, std::vector<IComposerClient::ContentType>*));
+ MOCK_METHOD2(setContentType, V2_4::Error(Display, IComposerClient::ContentType));
+ MOCK_METHOD5(setLayerGenericMetadata,
+ V2_4::Error(Display, Layer, const std::string&, bool,
+ const std::vector<uint8_t>&));
+ MOCK_METHOD1(getLayerGenericMetadataKeys,
+ V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
+ MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
index 6dc28bc..fe99e77 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -20,66 +20,82 @@
#include "DisplayHardware/HWC2.h"
-using HWC2::Error;
-using HWC2::Layer;
+using android::HWC2::Layer;
namespace android {
namespace Hwc2 {
namespace mock {
+namespace hal = android::hardware::graphics::composer::hal;
+
class Display : public HWC2::Display {
public:
+ using Layer = ::Layer;
+
Display();
~Display();
- MOCK_CONST_METHOD0(getId, hwc2_layer_t());
+ MOCK_CONST_METHOD0(getId, hal::HWDisplayId());
MOCK_CONST_METHOD0(isConnected, bool());
MOCK_METHOD1(setConnected, void(bool));
- MOCK_CONST_METHOD0(getCapabilities, const std::unordered_set<HWC2::DisplayCapability>&());
+ MOCK_CONST_METHOD0(getCapabilities, const std::unordered_set<hal::DisplayCapability>&());
- MOCK_METHOD0(acceptChanges, Error());
- MOCK_METHOD1(createLayer, Error(Layer**));
- MOCK_METHOD1(destroyLayer, Error(Layer*));
- MOCK_CONST_METHOD1(getActiveConfig, Error(std::shared_ptr<const Config>*));
- MOCK_CONST_METHOD1(getActiveConfigIndex, Error(int* outIndex));
- MOCK_METHOD1(getChangedCompositionTypes, Error(std::unordered_map<Layer*, HWC2::Composition>*));
- MOCK_CONST_METHOD1(getColorModes, Error(std::vector<android::ui::ColorMode>*));
+ MOCK_METHOD0(acceptChanges, hal::Error());
+ MOCK_METHOD1(createLayer, hal::Error(Layer**));
+ MOCK_METHOD1(destroyLayer, hal::Error(Layer*));
+ MOCK_CONST_METHOD1(getActiveConfig, hal::Error(std::shared_ptr<const Config>*));
+ MOCK_CONST_METHOD1(getActiveConfigIndex, hal::Error(int* outIndex));
+ MOCK_METHOD1(getChangedCompositionTypes,
+ hal::Error(std::unordered_map<Layer*, hal::Composition>*));
+ MOCK_CONST_METHOD1(getColorModes, hal::Error(std::vector<hal::ColorMode>*));
MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
MOCK_CONST_METHOD2(getRenderIntents,
- Error(android::ui::ColorMode, std::vector<android::ui::RenderIntent>*));
- MOCK_METHOD2(getDataspaceSaturationMatrix, Error(android::ui::Dataspace, android::mat4*));
+ hal::Error(hal::ColorMode, std::vector<hal::RenderIntent>*));
+ MOCK_METHOD2(getDataspaceSaturationMatrix, hal::Error(hal::Dataspace, android::mat4*));
MOCK_CONST_METHOD0(getConfigs, std::vector<std::shared_ptr<const Config>>());
- MOCK_CONST_METHOD1(getName, Error(std::string*));
+ MOCK_CONST_METHOD1(getName, hal::Error(std::string*));
MOCK_METHOD2(getRequests,
- Error(HWC2::DisplayRequest*, std::unordered_map<Layer*, HWC2::LayerRequest>*));
- MOCK_CONST_METHOD1(getType, Error(HWC2::DisplayType*));
- MOCK_CONST_METHOD1(supportsDoze, Error(bool*));
- MOCK_CONST_METHOD1(getHdrCapabilities, Error(android::HdrCapabilities*));
+ hal::Error(hal::DisplayRequest*, std::unordered_map<Layer*, hal::LayerRequest>*));
+ MOCK_CONST_METHOD1(getType, hal::Error(hal::DisplayType*));
+ MOCK_CONST_METHOD1(supportsDoze, hal::Error(bool*));
+ MOCK_CONST_METHOD1(getHdrCapabilities, hal::Error(android::HdrCapabilities*));
MOCK_CONST_METHOD3(getDisplayedContentSamplingAttributes,
- Error(android::ui::PixelFormat*, android::ui::Dataspace*, uint8_t*));
- MOCK_CONST_METHOD3(setDisplayContentSamplingEnabled, Error(bool, uint8_t, uint64_t));
+ hal::Error(hal::PixelFormat*, hal::Dataspace*, uint8_t*));
+ MOCK_CONST_METHOD3(setDisplayContentSamplingEnabled, hal::Error(bool, uint8_t, uint64_t));
MOCK_CONST_METHOD3(getDisplayedContentSample,
- Error(uint64_t, uint64_t, android::DisplayedFrameStats*));
- MOCK_CONST_METHOD1(getReleaseFences,
- Error(std::unordered_map<Layer*, android::sp<android::Fence>>* outFences));
- MOCK_METHOD1(present, Error(android::sp<android::Fence>*));
- MOCK_METHOD1(setActiveConfig, Error(const std::shared_ptr<const HWC2::Display::Config>&));
+ hal::Error(uint64_t, uint64_t, android::DisplayedFrameStats*));
+ MOCK_CONST_METHOD1(
+ getReleaseFences,
+ hal::Error(std::unordered_map<Layer*, android::sp<android::Fence>>* outFences));
+ MOCK_METHOD1(present, hal::Error(android::sp<android::Fence>*));
+ MOCK_METHOD1(setActiveConfig, hal::Error(const std::shared_ptr<const HWC2::Display::Config>&));
MOCK_METHOD4(setClientTarget,
- Error(uint32_t, const android::sp<android::GraphicBuffer>&,
- const android::sp<android::Fence>&, android::ui::Dataspace));
- MOCK_METHOD2(setColorMode, Error(android::ui::ColorMode, android::ui::RenderIntent));
- MOCK_METHOD2(setColorTransform, Error(const android::mat4&, android_color_transform_t));
+ hal::Error(uint32_t, const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&, hal::Dataspace));
+ MOCK_METHOD2(setColorMode, hal::Error(hal::ColorMode, hal::RenderIntent));
+ MOCK_METHOD2(setColorTransform, hal::Error(const android::mat4&, hal::ColorTransform));
MOCK_METHOD2(setOutputBuffer,
- Error(const android::sp<android::GraphicBuffer>&,
- const android::sp<android::Fence>&));
- MOCK_METHOD1(setPowerMode, Error(HWC2::PowerMode));
- MOCK_METHOD1(setVsyncEnabled, Error(HWC2::Vsync));
- MOCK_METHOD2(validate, Error(uint32_t*, uint32_t*));
+ hal::Error(const android::sp<android::GraphicBuffer>&,
+ const android::sp<android::Fence>&));
+ MOCK_METHOD1(setPowerMode, hal::Error(hal::PowerMode));
+ MOCK_METHOD1(setVsyncEnabled, hal::Error(hal::Vsync));
+ MOCK_METHOD2(validate, hal::Error(uint32_t*, uint32_t*));
MOCK_METHOD4(presentOrValidate,
- Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
- MOCK_CONST_METHOD1(setDisplayBrightness, Error(float));
+ hal::Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
+ MOCK_METHOD1(setDisplayBrightness, std::future<hal::Error>(float));
+ MOCK_CONST_METHOD1(getDisplayVsyncPeriod, hal::Error(nsecs_t*));
+ MOCK_METHOD3(setActiveConfigWithConstraints,
+ hal::Error(const std::shared_ptr<const HWC2::Display::Config>&,
+ const hal::VsyncPeriodChangeConstraints&,
+ hal::VsyncPeriodChangeTimeline*));
+ MOCK_METHOD1(setAutoLowLatencyMode, hal::Error(bool on));
+ MOCK_CONST_METHOD1(getSupportedContentTypes, hal::Error(std::vector<hal::ContentType>*));
+ MOCK_METHOD1(setContentType, hal::Error(hal::ContentType));
+ MOCK_METHOD1(getClientTargetProperty, hal::Error(hal::ClientTargetProperty*));
+ MOCK_CONST_METHOD1(getConnectionType, hal::Error(android::DisplayConnectionType*));
+ MOCK_CONST_METHOD0(isVsyncPeriodSwitchSupported, bool());
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 7c65f95..e22d0cf 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -29,7 +29,9 @@
PowerAdvisor();
~PowerAdvisor() override;
+ MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+ MOCK_METHOD0(notifyDisplayUpdateImminent, void());
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
index f6c4f62..1c8c44d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -17,6 +17,7 @@
#include "mock/MockDispSync.h"
#include <thread>
+using namespace std::chrono_literals;
namespace android {
namespace mock {
@@ -54,8 +55,9 @@
void DispSync::triggerCallback() {
if (mCallback.callback == nullptr) return;
- mCallback.callback->onDispSyncEvent(
- std::chrono::steady_clock::now().time_since_epoch().count());
+ const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch();
+ const auto expectedVSyncTime = now + 16ms;
+ mCallback.callback->onDispSyncEvent(now.count(), expectedVSyncTime.count());
}
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 9ca116d..b39487c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -31,15 +31,15 @@
MOCK_METHOD0(reset, void());
MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
MOCK_METHOD0(beginResync, void());
- MOCK_METHOD2(addResyncSample, bool(nsecs_t, bool*));
+ MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional<nsecs_t>, bool*));
MOCK_METHOD0(endResync, void());
MOCK_METHOD1(setPeriod, void(nsecs_t));
MOCK_METHOD0(getPeriod, nsecs_t());
MOCK_METHOD0(getIntendedPeriod, nsecs_t());
MOCK_METHOD1(setRefreshSkipCount, void(int));
- MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
+ MOCK_CONST_METHOD2(computeNextRefresh, nsecs_t(int, nsecs_t));
MOCK_METHOD1(setIgnorePresentFences, void(bool));
- MOCK_METHOD0(expectedPresentTime, nsecs_t());
+ MOCK_METHOD1(expectedPresentTime, nsecs_t(nsecs_t));
MOCK_CONST_METHOD1(dump, void(std::string&));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index ed35ebf..054aaf8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,14 +33,16 @@
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
- MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, int32_t));
+ MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
MOCK_METHOD1(registerDisplayEventConnection,
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+ MOCK_METHOD1(requestLatestConfig, void(const sp<android::EventThreadConnection> &));
MOCK_METHOD1(pauseVsyncCallback, void(bool));
+ MOCK_METHOD0(getEventThreadConnectionCount, size_t());
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
similarity index 75%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
rename to services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
index a7fd667..358dfdb 100644
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2019 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-#include "mock/gui/MockGraphicBufferProducer.h"
+#include "mock/MockFrameTracer.h"
namespace android {
namespace mock {
// Explicit default instantiation is recommended.
-GraphicBufferProducer::GraphicBufferProducer() = default;
-GraphicBufferProducer::~GraphicBufferProducer() = default;
+FrameTracer::FrameTracer() = default;
+FrameTracer::~FrameTracer() = default;
} // namespace mock
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
new file mode 100644
index 0000000..f768b81
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "FrameTracer/FrameTracer.h"
+
+namespace android {
+namespace mock {
+
+class FrameTracer : public android::FrameTracer {
+public:
+ FrameTracer();
+ ~FrameTracer();
+
+ MOCK_METHOD0(initialize, void());
+ MOCK_METHOD0(registerDataSource, void());
+ MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
+ MOCK_METHOD6(traceTimestamp,
+ void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD6(traceFence,
+ void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
+ FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD0(miniDump, std::string());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
new file mode 100644
index 0000000..078d8e07
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "Layer.h"
+
+namespace android::mock {
+
+class MockLayer : public Layer {
+public:
+ MockLayer(SurfaceFlinger* flinger, std::string name)
+ : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 800, 600, 0, {})) {}
+ explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
+
+ MOCK_CONST_METHOD0(getType, const char*());
+ MOCK_METHOD0(getFrameSelectionPriority, int32_t());
+ MOCK_CONST_METHOD0(isVisible, bool());
+ MOCK_METHOD0(createClone, sp<Layer>());
+ MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
+};
+
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
index 97a13e4..5fb06fd 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
@@ -16,12 +16,15 @@
#include "mock/MockMessageQueue.h"
-namespace android {
-namespace mock {
+namespace android::mock {
-// Explicit default instantiation is recommended.
-MessageQueue::MessageQueue() = default;
+MessageQueue::MessageQueue() {
+ ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
+ // Execute task to prevent broken promise exception on destruction.
+ handler->handleMessage(Message());
+ });
+}
+
MessageQueue::~MessageQueue() = default;
-} // namespace mock
-} // namespace android
\ No newline at end of file
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index 1b1c1a7..a82b583 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -21,8 +21,7 @@
#include "Scheduler/EventThread.h"
#include "Scheduler/MessageQueue.h"
-namespace android {
-namespace mock {
+namespace android::mock {
class MessageQueue : public android::MessageQueue {
public:
@@ -30,13 +29,11 @@
~MessageQueue() override;
MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
- MOCK_METHOD2(setEventThread, void(android::EventThread*, ResyncCallback));
MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
MOCK_METHOD0(waitMessage, void());
- MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
+ MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
MOCK_METHOD0(invalidate, void());
MOCK_METHOD0(refresh, void());
};
-} // namespace mock
-} // namespace android
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
index 4129328..7e925b9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include "mock/MockSurfaceInterceptor.h"
namespace android {
@@ -25,3 +29,6 @@
} // namespace mock
} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index 458b2f3..5beee1c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -39,7 +39,7 @@
const Vector<DisplayState>&, uint32_t));
MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
- MOCK_METHOD4(saveBufferUpdate, void(const sp<const Layer>&, uint32_t, uint32_t, uint64_t));
+ MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t));
MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&));
MOCK_METHOD1(saveDisplayDeletion, void(int32_t));
MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index b1634a8..4186e2b 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,13 +28,23 @@
TimeStats();
~TimeStats() override;
+ MOCK_METHOD0(onBootFinished, void());
MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
MOCK_METHOD0(isEnabled, bool());
MOCK_METHOD0(miniDump, std::string());
MOCK_METHOD0(incrementTotalFrames, void());
MOCK_METHOD0(incrementMissedFrames, void());
MOCK_METHOD0(incrementClientCompositionFrames, void());
+ MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
+ MOCK_METHOD0(incrementRefreshRateSwitches, void());
+ MOCK_METHOD0(incrementCompositionStrategyChanges, void());
+ MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
+ MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
+ MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
+ MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));
MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
+ MOCK_METHOD2(incrementLatchSkipped, void(int32_t layerId, LatchSkipReason reason));
+ MOCK_METHOD1(incrementBadDesiredPresent, void(int32_t layerId));
MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
@@ -43,7 +53,8 @@
MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
MOCK_METHOD1(onDestroy, void(int32_t));
MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
- MOCK_METHOD1(setPowerMode, void(int32_t));
+ MOCK_METHOD1(setPowerMode,
+ void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode));
MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
};
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
deleted file mode 100644
index a17b73f..0000000
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "mock/gui/MockGraphicBufferConsumer.h"
-
-namespace android {
-namespace mock {
-
-// Explicit default instantiation is recommended.
-GraphicBufferConsumer::GraphicBufferConsumer() = default;
-GraphicBufferConsumer::~GraphicBufferConsumer() = default;
-
-} // namespace mock
-} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
deleted file mode 100644
index 98f24c2..0000000
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gmock/gmock.h>
-
-#include <gui/IGraphicBufferConsumer.h>
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace mock {
-
-class GraphicBufferConsumer : public BnGraphicBufferConsumer, public virtual android::RefBase {
-public:
- GraphicBufferConsumer();
- ~GraphicBufferConsumer() override;
-
- MOCK_METHOD3(acquireBuffer, status_t(BufferItem*, nsecs_t, uint64_t));
- MOCK_METHOD1(detachBuffer, status_t(int));
- MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&));
- MOCK_METHOD5(releaseBuffer, status_t(int, uint64_t, EGLDisplay, EGLSyncKHR, const sp<Fence>&));
- MOCK_METHOD2(consumerConnect, status_t(const sp<IConsumerListener>&, bool));
- MOCK_METHOD0(consumerDisconnect, status_t());
- MOCK_METHOD1(getReleasedBuffers, status_t(uint64_t*));
- MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t));
- MOCK_METHOD1(setMaxBufferCount, status_t(int));
- MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int));
- MOCK_METHOD1(setConsumerName, status_t(const String8&));
- MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat));
- MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace));
- MOCK_METHOD1(setConsumerUsageBits, status_t(uint64_t));
- MOCK_METHOD1(setConsumerIsProtected, status_t(bool));
- MOCK_METHOD1(setTransformHint, status_t(uint32_t));
- MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*));
- MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*));
- MOCK_METHOD0(discardFreeBuffers, status_t());
- MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*));
-};
-
-} // namespace mock
-} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
deleted file mode 100644
index c98f39f..0000000
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gmock/gmock.h>
-
-#include <gui/IGraphicBufferProducer.h>
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace mock {
-
-class GraphicBufferProducer : public BnGraphicBufferProducer, public virtual android::RefBase {
-public:
- GraphicBufferProducer();
- ~GraphicBufferProducer() override;
-
- MOCK_METHOD2(requestBuffer, status_t(int, sp<GraphicBuffer>*));
- MOCK_METHOD1(setMaxDequeuedBufferCount, status_t(int));
- MOCK_METHOD1(setAsyncMode, status_t(bool));
- MOCK_METHOD8(dequeueBuffer,
- status_t(int*, sp<Fence>*, uint32_t, uint32_t, PixelFormat, uint64_t, uint64_t*,
- FrameEventHistoryDelta*));
- MOCK_METHOD1(detachBuffer, status_t(int));
- MOCK_METHOD2(detachNextBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*));
- MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&));
- MOCK_METHOD3(queueBuffer, status_t(int, const QueueBufferInput&, QueueBufferOutput*));
- MOCK_METHOD2(cancelBuffer, status_t(int, const sp<Fence>&));
- MOCK_METHOD2(query, int(int, int*));
- MOCK_METHOD4(connect, status_t(const sp<IProducerListener>&, int, bool, QueueBufferOutput*));
- MOCK_METHOD2(disconnect, status_t(int, DisconnectMode));
- MOCK_METHOD1(setSidebandStream, status_t(const sp<NativeHandle>&));
- MOCK_METHOD4(allocateBuffers, void(uint32_t, uint32_t, PixelFormat, uint64_t));
- MOCK_METHOD1(allowAllocation, status_t(bool));
- MOCK_METHOD1(setGenerationNumber, status_t(uint32_t));
- MOCK_CONST_METHOD0(getConsumerName, String8());
- MOCK_METHOD1(setSharedBufferMode, status_t(bool));
- MOCK_METHOD1(setAutoRefresh, status_t(bool));
- MOCK_METHOD1(setDequeueTimeout, status_t(nsecs_t));
- MOCK_METHOD3(getLastQueuedBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*, float[16]));
- MOCK_METHOD1(getFrameTimestamps, void(FrameEventHistoryDelta*));
- MOCK_CONST_METHOD1(getUniqueId, status_t(uint64_t*));
- MOCK_CONST_METHOD1(getConsumerUsage, status_t(uint64_t*));
-};
-
-} // namespace mock
-} // namespace android
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
new file mode 100644
index 0000000..1318deb
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2019 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 <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+#include <ui/Fence.h>
+#include <utils/Timers.h>
+#include <thread>
+
+namespace android {
+
+namespace {
+
+struct CallbackData {
+ CallbackData() = default;
+ CallbackData(nsecs_t time, const sp<Fence>& fence,
+ const std::vector<SurfaceControlStats>& stats)
+ : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
+
+ nsecs_t latchTime;
+ sp<Fence> presentFence;
+ std::vector<SurfaceControlStats> surfaceControlStats;
+};
+
+class ExpectedResult {
+public:
+ enum Transaction {
+ NOT_PRESENTED = 0,
+ PRESENTED,
+ };
+
+ enum Buffer {
+ NOT_ACQUIRED = 0,
+ ACQUIRED,
+ };
+
+ enum PreviousBuffer {
+ NOT_RELEASED = 0,
+ RELEASED,
+ UNKNOWN,
+ };
+
+ void reset() {
+ mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ mExpectedSurfaceResults.clear();
+ }
+
+ void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
+ ExpectedResult::Buffer bufferResult = ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ mTransactionResult = transactionResult;
+ mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
+ std::forward_as_tuple(bufferResult, previousBufferResult));
+ }
+
+ void addSurfaces(ExpectedResult::Transaction transactionResult,
+ const std::vector<sp<SurfaceControl>>& layers,
+ ExpectedResult::Buffer bufferResult = ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ for (const auto& layer : layers) {
+ addSurface(transactionResult, layer, bufferResult, previousBufferResult);
+ }
+ }
+
+ void addExpectedPresentTime(nsecs_t expectedPresentTime) {
+ mExpectedPresentTime = expectedPresentTime;
+ }
+
+ void verifyCallbackData(const CallbackData& callbackData) const {
+ const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
+ if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
+ ASSERT_GE(latchTime, 0) << "bad latch time";
+ ASSERT_NE(presentFence, nullptr);
+ if (mExpectedPresentTime >= 0) {
+ ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
+ ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
+ // if the panel is running at 30 hz, at the worst case, our expected time just
+ // misses vsync and we have to wait another 33.3ms
+ ASSERT_LE(presentFence->getSignalTime(),
+ mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
+ }
+ } else {
+ ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
+ ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
+ }
+
+ ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
+ << "wrong number of surfaces";
+
+ for (const auto& stats : surfaceControlStats) {
+ ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
+
+ const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
+ ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
+ << "unexpected surface control";
+ expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
+ }
+ }
+
+private:
+ class ExpectedSurfaceResult {
+ public:
+ ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
+ ExpectedResult::PreviousBuffer previousBufferResult)
+ : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
+
+ void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
+ nsecs_t latchTime) const {
+ const auto&
+ [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
+ transformHint,
+ frameEvents] = surfaceControlStats;
+
+ ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+ << "bad acquire time";
+ ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+
+ if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+ ASSERT_NE(previousReleaseFence, nullptr)
+ << "failed to set release prev buffer fence";
+ } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+ ASSERT_EQ(previousReleaseFence, nullptr)
+ << "should not have set released prev buffer fence";
+ }
+ }
+
+ private:
+ ExpectedResult::Buffer mBufferResult;
+ ExpectedResult::PreviousBuffer mPreviousBufferResult;
+ };
+
+ struct SCHash {
+ std::size_t operator()(const sp<SurfaceControl>& sc) const {
+ return std::hash<IBinder*>{}(sc->getHandle().get());
+ }
+ };
+ ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ nsecs_t mExpectedPresentTime = -1;
+ std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
+};
+
+class CallbackHelper {
+public:
+ static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ if (!callbackContext) {
+ ALOGE("failed to get callback context");
+ }
+ CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
+ std::lock_guard lock(helper->mMutex);
+ helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
+ helper->mConditionVariable.notify_all();
+ }
+
+ void getCallbackData(CallbackData* outData) {
+ std::unique_lock lock(mMutex);
+
+ if (mCallbackDataQueue.empty()) {
+ ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ *outData = std::move(mCallbackDataQueue.front());
+ mCallbackDataQueue.pop();
+ }
+
+ void verifyFinalState() {
+ // Wait to see if there are extra callbacks
+ std::this_thread::sleep_for(500ms);
+
+ std::lock_guard lock(mMutex);
+ EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ mCallbackDataQueue = {};
+ }
+
+ void* getContext() { return static_cast<void*>(this); }
+
+ std::mutex mMutex;
+ std::condition_variable mConditionVariable;
+ std::queue<CallbackData> mCallbackDataQueue;
+};
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h
new file mode 100644
index 0000000..07916b6
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/ColorUtils.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 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 <ui/ColorSpace.h>
+
+namespace android {
+
+namespace {
+
+struct Color {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+
+ static const Color RED;
+ static const Color GREEN;
+ static const Color BLUE;
+ static const Color WHITE;
+ static const Color BLACK;
+ static const Color TRANSPARENT;
+};
+
+const Color Color::RED{255, 0, 0, 255};
+const Color Color::GREEN{0, 255, 0, 255};
+const Color Color::BLUE{0, 0, 255, 255};
+const Color Color::WHITE{255, 255, 255, 255};
+const Color Color::BLACK{0, 0, 0, 255};
+const Color Color::TRANSPARENT{0, 0, 0, 0};
+
+class ColorTransformHelper {
+public:
+ static void DegammaColorSingle(half& s) {
+ if (s <= 0.03928f)
+ s = s / 12.92f;
+ else
+ s = pow((s + 0.055f) / 1.055f, 2.4f);
+ }
+
+ static void DegammaColor(half3& color) {
+ DegammaColorSingle(color.r);
+ DegammaColorSingle(color.g);
+ DegammaColorSingle(color.b);
+ }
+
+ static void GammaColorSingle(half& s) {
+ if (s <= 0.0031308f) {
+ s = s * 12.92f;
+ } else {
+ s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+ }
+ }
+
+ static void GammaColor(half3& color) {
+ GammaColorSingle(color.r);
+ GammaColorSingle(color.g);
+ GammaColorSingle(color.b);
+ }
+
+ static void applyMatrix(half3& color, const mat3& mat) {
+ half3 ret = half3(0);
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ ret[i] = ret[i] + color[j] * mat[j][i];
+ }
+ }
+ color = ret;
+ }
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
new file mode 100644
index 0000000..5480b00
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2019 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 <ui/Rect.h>
+#include <utils/String8.h>
+#include "TransactionUtils.h"
+
+namespace android {
+
+namespace {
+
+// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
+// individual pixel values for testing purposes.
+class ScreenCapture : public RefBase {
+public:
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
+ captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
+ }
+
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
+ const auto sf = ComposerService::getComposerService();
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+ Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+ Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ static void captureChildLayersExcluding(
+ std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+ std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR,
+ sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
+ 1.0f, true));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+ TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
+ }
+
+ void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+ const bool leftBorder = rect.left > 0;
+ const bool topBorder = rect.top > 0;
+ const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
+ const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
+
+ if (topBorder) {
+ Rect top(rect.left, rect.top - 1, rect.right, rect.top);
+ if (leftBorder) {
+ top.left -= 1;
+ }
+ if (rightBorder) {
+ top.right += 1;
+ }
+ expectColor(top, color, tolerance);
+ }
+ if (leftBorder) {
+ Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
+ expectColor(left, color, tolerance);
+ }
+ if (rightBorder) {
+ Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
+ expectColor(right, color, tolerance);
+ }
+ if (bottomBorder) {
+ Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
+ if (leftBorder) {
+ bottom.left -= 1;
+ }
+ if (rightBorder) {
+ bottom.right += 1;
+ }
+ expectColor(bottom, color, tolerance);
+ }
+ }
+
+ void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
+ const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
+ uint8_t tolerance = 0) {
+ ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
+
+ const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
+ const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
+ // avoid checking borders due to unspecified filtering behavior
+ const int32_t offsetX = filtered ? 2 : 0;
+ const int32_t offsetY = filtered ? 2 : 0;
+ expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
+ tolerance);
+ expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
+ tolerance);
+ expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
+ tolerance);
+ expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
+ bottomRight, tolerance);
+ }
+
+ void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+ const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
+ if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+ String8 err(String8::format("pixel @ (%3d, %3d): "
+ "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+ x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+ EXPECT_EQ(String8(), err) << err.string();
+ }
+ }
+
+ void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
+
+ void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
+
+ void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
+
+ explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+ mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
+ }
+
+ ~ScreenCapture() { mOutBuffer->unlock(); }
+
+private:
+ sp<GraphicBuffer> mOutBuffer;
+ uint8_t* mPixels = nullptr;
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
new file mode 100644
index 0000000..8e1f943
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2019 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 <chrono>
+
+#include <android/native_window.h>
+#include <binder/IPCThreadState.h>
+#include <gtest/gtest.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "ColorUtils.h"
+
+namespace android {
+
+namespace {
+
+using namespace std::chrono_literals;
+using Transaction = SurfaceComposerClient::Transaction;
+
+std::ostream& operator<<(std::ostream& os, const Color& color) {
+ os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
+ return os;
+}
+
+class TransactionUtils {
+public:
+ // Fill a region with the specified color.
+ static 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;
+ }
+
+ 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;
+ dst[3] = color.a;
+ dst += 4;
+ }
+ }
+ }
+
+ // Fill a region with the specified color.
+ static 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.
+ static void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels,
+ const Rect& rect, const Color& color, uint8_t tolerance) {
+ int32_t x = rect.left;
+ int32_t y = rect.top;
+ int32_t width = rect.right - rect.left;
+ int32_t height = rect.bottom - rect.top;
+
+ int32_t bufferWidth = int32_t(outBuffer->getWidth());
+ int32_t bufferHeight = int32_t(outBuffer->getHeight());
+ if (x + width > bufferWidth) {
+ x = std::min(x, bufferWidth);
+ width = bufferWidth - x;
+ }
+ if (y + height > bufferHeight) {
+ y = std::min(y, bufferHeight);
+ height = bufferHeight - y;
+ }
+
+ auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
+ uint8_t tmp = a >= b ? a - b : b - a;
+ return tmp <= tolerance;
+ };
+ for (int32_t j = 0; j < height; j++) {
+ const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
+ for (int32_t i = 0; i < width; i++) {
+ const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
+ EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
+ << "pixel @ (" << x + i << ", " << y + j << "): "
+ << "expected (" << color << "), "
+ << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
+ src += 4;
+ }
+ }
+ }
+
+ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const Color& color,
+ bool unlock = true) {
+ fillSurfaceRGBA8(sc, color.r, color.g, color.b, unlock);
+ }
+
+ // Fill an RGBA_8888 formatted surface with a single color.
+ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
+ bool unlock = true) {
+ ANativeWindow_Buffer outBuffer;
+ sp<Surface> s = sc->getSurface();
+ ASSERT_TRUE(s != nullptr);
+ ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
+ uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+ for (int y = 0; y < outBuffer.height; y++) {
+ for (int x = 0; x < outBuffer.width; x++) {
+ uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
+ pixel[0] = r;
+ pixel[1] = g;
+ pixel[2] = b;
+ pixel[3] = 255;
+ }
+ }
+ if (unlock) {
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ }
+ }
+};
+
+enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
+
+// Environment for starting up binder threads. This is required for testing
+// virtual displays, as BufferQueue parameters may be queried over binder.
+class BinderEnvironment : public ::testing::Environment {
+public:
+ void SetUp() override { ProcessState::self()->startThreadPool(); }
+};
+
+/** RAII Wrapper around get/seteuid */
+class UIDFaker {
+ uid_t oldId;
+
+public:
+ UIDFaker(uid_t uid) {
+ oldId = geteuid();
+ seteuid(uid);
+ }
+ ~UIDFaker() { seteuid(oldId); }
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index a1b45e6..667dfb9 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -14,6 +14,10 @@
* limitations under the License.
*/
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
#include <android/looper.h>
#include <gui/DisplayEventReceiver.h>
#include <utils/Looper.h>
@@ -82,3 +86,6 @@
return 0;
}
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"