Merge "flatland: ConsumerBase-based classes now create their own BufferQueues" into main
diff --git a/Android.bp b/Android.bp
index 4befb1b..72311f0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -38,6 +38,7 @@
cc_library_headers {
name: "native_headers",
+ vendor_available: true,
host_supported: true,
target: {
windows: {
diff --git a/include/input/Resampler.h b/include/input/Resampler.h
index ff9c4b0..5980d5d 100644
--- a/include/input/Resampler.h
+++ b/include/input/Resampler.h
@@ -44,7 +44,7 @@
* samples by the end of the resampling. No other field of motionEvent should be modified.
* - If resampling does not occur, then motionEvent must not be modified in any way.
*/
- virtual void resampleMotionEvent(const std::chrono::nanoseconds resampleTime,
+ virtual void resampleMotionEvent(std::chrono::nanoseconds resampleTime,
MotionEvent& motionEvent,
const InputMessage* futureSample) = 0;
};
@@ -60,7 +60,7 @@
* data, LegacyResampler will extrapolate. Otherwise, no resampling takes place and
* `motionEvent` is unmodified.
*/
- void resampleMotionEvent(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent,
+ void resampleMotionEvent(std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent,
const InputMessage* futureSample) override;
private:
@@ -72,10 +72,6 @@
struct Sample {
std::chrono::nanoseconds eventTime;
Pointer pointer;
-
- Sample(const std::chrono::nanoseconds eventTime, const PointerProperties& properties,
- const PointerCoords& coords)
- : eventTime{eventTime}, pointer{properties, coords} {}
};
/**
@@ -99,17 +95,34 @@
void updateLatestSamples(const MotionEvent& motionEvent);
/**
- * May add a sample at the end of motionEvent with eventTime equal to resampleTime, and
- * interpolated coordinates between the latest motionEvent sample and futureSample.
+ * Checks if there are necessary conditions to interpolate. For example, interpolation cannot
+ * take place if samples are too far apart in time. mLatestSamples must have at least one sample
+ * when canInterpolate is invoked.
*/
- void interpolate(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent,
- const InputMessage& futureSample) const;
+ bool canInterpolate(const InputMessage& futureSample) const;
/**
- * May add a sample at the end of motionEvent by extrapolating from the latest two samples. The
- * added sample either has eventTime equal to resampleTime, or an earlier time if resampleTime
- * is too far in the future.
+ * Returns a sample interpolated between the latest sample of mLatestSamples and futureSample,
+ * if the conditions from canInterpolate are satisfied. Otherwise, returns nullopt.
+ * mLatestSamples must have at least one sample when attemptInterpolation is called.
*/
- void extrapolate(const std::chrono::nanoseconds resampleTime, MotionEvent& motionEvent) const;
+ std::optional<Sample> attemptInterpolation(std::chrono::nanoseconds resampleTime,
+ const InputMessage& futureSample) const;
+
+ /**
+ * Checks if there are necessary conditions to extrapolate. That is, there are at least two
+ * samples in mLatestSamples, and delta is bounded within a time interval.
+ */
+ bool canExtrapolate() const;
+
+ /**
+ * Returns a sample extrapolated from the two samples of mLatestSamples, if the conditions from
+ * canExtrapolate are satisfied. The returned sample either has eventTime equal to resampleTime,
+ * or an earlier time if resampleTime is too far in the future. If canExtrapolate returns false,
+ * this function returns nullopt.
+ */
+ std::optional<Sample> attemptExtrapolation(std::chrono::nanoseconds resampleTime) const;
+
+ inline static void addSampleToMotionEvent(const Sample& sample, MotionEvent& motionEvent);
};
} // namespace android
\ No newline at end of file
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 26c228d..4e02ace 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -255,6 +255,9 @@
"include_cpp/android/*.h",
],
license: "NOTICE",
+ // These are intentionally not C. It's a mistake that they're in the NDK.
+ // See the bug above.
+ skip_verification: true,
}
ndk_library {
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index cd78e82..3038de9 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -1384,8 +1384,8 @@
sp<IServiceManager> sm = defaultServiceManager();
ASSERT_NE(nullptr, sm);
// Any Java service with non-empty getInterfaceDescriptor() would do.
- // Let's pick batteryproperties.
- auto binder = sm->checkService(String16("batteryproperties"));
+ // Let's pick activity.
+ auto binder = sm->checkService(String16("activity"));
ASSERT_NE(nullptr, binder);
auto descriptor = binder->getInterfaceDescriptor();
ASSERT_GE(descriptor.size(), 0u);
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 3d1be4d..462081b 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -116,7 +116,7 @@
// Public for testing.
static nsecs_t snapToNextTick(
nsecs_t timestamp, nsecs_t tickPhase, nsecs_t tickInterval);
- nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; };
+ nsecs_t getReportedCompositeDeadline() const { return mCompositorTiming.deadline; }
nsecs_t getNextCompositeDeadline(const nsecs_t now) const;
nsecs_t getCompositeInterval() const { return mCompositorTiming.interval; }
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 8fca946..3aac457 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -867,6 +867,6 @@
#endif
// ----------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_GUI_IGRAPHICBUFFERPRODUCER_H
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 39207f8..0f51f2d 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -194,6 +194,14 @@
* in <system/window.h>. */
int setScalingMode(int mode);
+ virtual int setBuffersTimestamp(int64_t timestamp);
+ virtual int setBuffersDataSpace(ui::Dataspace dataSpace);
+ virtual int setCrop(Rect const* rect);
+ virtual int setBuffersTransform(uint32_t transform);
+ virtual int setBuffersStickyTransform(uint32_t transform);
+ virtual int setBuffersFormat(PixelFormat format);
+ virtual int setUsage(uint64_t reqUsage);
+
// See IGraphicBufferProducer::setDequeueTimeout
status_t setDequeueTimeout(nsecs_t timeout);
@@ -354,16 +362,9 @@
virtual int connect(int api);
virtual int setBufferCount(int bufferCount);
virtual int setBuffersUserDimensions(uint32_t width, uint32_t height);
- virtual int setBuffersFormat(PixelFormat format);
- virtual int setBuffersTransform(uint32_t transform);
- virtual int setBuffersStickyTransform(uint32_t transform);
- virtual int setBuffersTimestamp(int64_t timestamp);
- virtual int setBuffersDataSpace(ui::Dataspace dataSpace);
virtual int setBuffersSmpte2086Metadata(const android_smpte2086_metadata* metadata);
virtual int setBuffersCta8613Metadata(const android_cta861_3_metadata* metadata);
virtual int setBuffersHdr10PlusMetadata(const size_t size, const uint8_t* metadata);
- virtual int setCrop(Rect const* rect);
- virtual int setUsage(uint64_t reqUsage);
virtual void setSurfaceDamage(android_native_rect_t* rects, size_t numRects);
public:
diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
index b7aba2b..7ddac81 100644
--- a/libs/gui/include/gui/view/Surface.h
+++ b/libs/gui/include/gui/view/Surface.h
@@ -59,8 +59,9 @@
// of the full parceling to happen on its native side.
status_t readFromParcel(const Parcel* parcel, bool nameAlreadyRead);
- private:
+ std::string toString() const;
+private:
static String16 readMaybeEmptyString16(const Parcel* parcel);
};
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 1b216e9..f07747f 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -12,6 +12,34 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+aidl_interface {
+ name: "libgui_test_server_aidl",
+ unstable: true,
+ srcs: ["testserver/aidl/**/*.aidl"],
+ local_include_dir: "testserver/aidl",
+ include_dirs: [
+ "frameworks/native/aidl/gui",
+ ],
+ backend: {
+ cpp: {
+ enabled: true,
+ additional_shared_libraries: [
+ "libgui",
+ "libui",
+ ],
+ },
+ java: {
+ enabled: false,
+ },
+ ndk: {
+ enabled: false,
+ },
+ rust: {
+ enabled: false,
+ },
+ },
+}
+
cc_test {
name: "libgui_test",
test_suites: ["device-tests"],
@@ -30,7 +58,6 @@
],
srcs: [
- "LibGuiMain.cpp", // Custom gtest entrypoint
"BLASTBufferQueue_test.cpp",
"BufferItemConsumer_test.cpp",
"BufferQueue_test.cpp",
@@ -38,24 +65,29 @@
"Choreographer_test.cpp",
"CompositorTiming_test.cpp",
"CpuConsumer_test.cpp",
- "EndToEndNativeInputTest.cpp",
- "FrameRateUtilsTest.cpp",
- "DisplayInfo_test.cpp",
"DisplayedContentSampling_test.cpp",
+ "DisplayInfo_test.cpp",
+ "EndToEndNativeInputTest.cpp",
"FillBuffer.cpp",
+ "FrameRateUtilsTest.cpp",
"GLTest.cpp",
"IGraphicBufferProducer_test.cpp",
+ "LibGuiMain.cpp", // Custom gtest entrypoint
"Malicious.cpp",
"MultiTextureConsumer_test.cpp",
"RegionSampling_test.cpp",
"StreamSplitter_test.cpp",
+ "Surface_test.cpp",
"SurfaceTextureClient_test.cpp",
"SurfaceTextureFBO_test.cpp",
+ "SurfaceTextureGL_test.cpp",
"SurfaceTextureGLThreadToGL_test.cpp",
"SurfaceTextureGLToGL_test.cpp",
- "SurfaceTextureGL_test.cpp",
"SurfaceTextureMultiContextGL_test.cpp",
- "Surface_test.cpp",
+ "TestServer_test.cpp",
+ "testserver/TestServer.cpp",
+ "testserver/TestServerClient.cpp",
+ "testserver/TestServerHost.cpp",
"TextureRenderer.cpp",
"VsyncEventData_test.cpp",
"WindowInfo_test.cpp",
@@ -66,10 +98,17 @@
"android.hardware.configstore-utils",
"libSurfaceFlingerProp",
"libGLESv1_CM",
+ "libgui_test_server_aidl-cpp",
"libinput",
"libnativedisplay",
],
+ // This needs to get copied over for the test since it's not part of the
+ // platform.
+ data_libs: [
+ "libgui_test_server_aidl-cpp",
+ ],
+
static_libs: [
"libgmock",
],
diff --git a/libs/gui/tests/LibGuiMain.cpp b/libs/gui/tests/LibGuiMain.cpp
index 10f7207..7c7c2cc 100644
--- a/libs/gui/tests/LibGuiMain.cpp
+++ b/libs/gui/tests/LibGuiMain.cpp
@@ -14,8 +14,15 @@
* limitations under the License.
*/
-#include "gtest/gtest.h"
-#include "log/log.h"
+#include <android-base/unique_fd.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+#include "testserver/TestServer.h"
+#include "testserver/TestServerClient.h"
+#include "testserver/TestServerHost.h"
+
+using namespace android;
namespace {
@@ -32,7 +39,34 @@
} // namespace
int main(int argc, char** argv) {
+ // There are three modes that we can run in to support the libgui TestServer:
+ //
+ // - libgui_test : normal mode, runs tests and fork/execs the testserver host process
+ // - libgui_test --test-server-host $recvPipeFd $sendPipeFd : TestServerHost mode, listens on
+ // $recvPipeFd for commands and sends responses over $sendPipeFd
+ // - libgui_test --test-server $name : TestServer mode, starts a ITestService binder service
+ // under $name
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg == "--test-server-host") {
+ LOG_ALWAYS_FATAL_IF(argc < (i + 2), "--test-server-host requires two pipe fds");
+ // Note that the send/recv are from our perspective.
+ base::unique_fd recvPipeFd = base::unique_fd(atoi(argv[i + 1]));
+ base::unique_fd sendPipeFd = base::unique_fd(atoi(argv[i + 2]));
+ return TestServerHostMain(argv[0], std::move(sendPipeFd), std::move(recvPipeFd));
+ }
+ if (arg == "--test-server") {
+ LOG_ALWAYS_FATAL_IF(argc < (i + 1), "--test-server requires a name");
+ return TestServerMain(argv[i + 1]);
+ }
+ }
testing::InitGoogleTest(&argc, argv);
testing::UnitTest::GetInstance()->listeners().Append(new TestCaseLogger());
+
+ // This has to be run *before* any test initialization, because it fork/execs a TestServerHost,
+ // which will later create new binder service. You can't do that in a forked thread after you've
+ // initialized any binder stuff, which some tests do.
+ TestServerClient::InitializeOrDie(argv[0]);
+
return RUN_ALL_TESTS();
}
\ No newline at end of file
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 8ab8783..4232443 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "gui/view/Surface.h"
#include "Constants.h"
#include "MockConsumer.h"
@@ -53,6 +54,8 @@
#include <limits>
#include <thread>
+#include "testserver/TestServerClient.h"
+
namespace android {
using namespace std::chrono_literals;
@@ -2363,6 +2366,14 @@
EXPECT_EQ(OK, surface->disconnect(NATIVE_WINDOW_API_CPU));
}
+
+TEST_F(SurfaceTest, ViewSurface_toString) {
+ view::Surface surface{};
+ EXPECT_EQ("", surface.toString());
+
+ surface.name = String16("name");
+ EXPECT_EQ("name", surface.toString());
+}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS)
} // namespace android
diff --git a/libs/gui/tests/TestServer_test.cpp b/libs/gui/tests/TestServer_test.cpp
new file mode 100644
index 0000000..8712988
--- /dev/null
+++ b/libs/gui/tests/TestServer_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 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 <gtest/gtest.h>
+
+#include <SurfaceFlingerProperties.h>
+#include <android/gui/IDisplayEventConnection.h>
+#include <android/gui/ISurfaceComposer.h>
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware_buffer.h>
+#include <binder/ProcessState.h>
+#include <com_android_graphics_libgui_flags.h>
+#include <configstore/Utils.h>
+#include <gui/AidlStatusUtil.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/BufferQueue.h>
+#include <gui/CpuConsumer.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SyncScreenCaptureListener.h>
+#include <private/gui/ComposerService.h>
+#include <private/gui/ComposerServiceAIDL.h>
+#include <sys/types.h>
+#include <system/window.h>
+#include <ui/BufferQueueDefs.h>
+#include <ui/DisplayMode.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <utils/Errors.h>
+#include <utils/String8.h>
+
+#include <cstddef>
+#include <limits>
+#include <thread>
+
+#include "binder/IInterface.h"
+#include "testserver/TestServerClient.h"
+
+namespace android {
+
+namespace {
+
+class TestServerTest : public ::testing::Test {
+protected:
+ TestServerTest() { ProcessState::self()->startThreadPool(); }
+};
+
+} // namespace
+
+TEST_F(TestServerTest, Create) {
+ EXPECT_NE(nullptr, TestServerClient::Create());
+}
+
+TEST_F(TestServerTest, CreateProducer) {
+ sp<TestServerClient> client = TestServerClient::Create();
+ EXPECT_NE(nullptr, client->CreateProducer());
+}
+
+TEST_F(TestServerTest, KillServer) {
+ class DeathWaiter : public IBinder::DeathRecipient {
+ public:
+ virtual void binderDied(const wp<IBinder>&) override { mPromise.set_value(true); }
+ std::future<bool> getFuture() { return mPromise.get_future(); }
+
+ std::promise<bool> mPromise;
+ };
+
+ sp<TestServerClient> client = TestServerClient::Create();
+ sp<IGraphicBufferProducer> producer = client->CreateProducer();
+ EXPECT_NE(nullptr, producer);
+
+ sp<DeathWaiter> deathWaiter = sp<DeathWaiter>::make();
+ EXPECT_EQ(OK, IInterface::asBinder(producer)->linkToDeath(deathWaiter));
+
+ auto deathWaiterFuture = deathWaiter->getFuture();
+ EXPECT_EQ(OK, client->Kill());
+ EXPECT_EQ(nullptr, client->CreateProducer());
+
+ EXPECT_TRUE(deathWaiterFuture.get());
+}
+
+} // namespace android
diff --git a/libs/gui/tests/testserver/TestServer.cpp b/libs/gui/tests/testserver/TestServer.cpp
new file mode 100644
index 0000000..cd8824e
--- /dev/null
+++ b/libs/gui/tests/testserver/TestServer.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TestServer"
+
+#include <android-base/stringprintf.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Status.h>
+#include <gui/BufferQueue.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/view/Surface.h>
+#include <libgui_test_server/BnTestServer.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+#include <cstdint>
+#include <cstdlib>
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "TestServer.h"
+
+namespace android {
+
+namespace {
+class TestConsumerListener : public BnConsumerListener {
+ virtual void onFrameAvailable(const BufferItem&) override {}
+ virtual void onBuffersReleased() override {}
+ virtual void onSidebandStreamChanged() override {}
+};
+
+class TestServiceImpl : public libgui_test_server::BnTestServer {
+public:
+ TestServiceImpl(const char* name) : mName(name) {}
+
+ virtual binder::Status createProducer(view::Surface* out) override {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ BufferQueueHolder bq;
+ BufferQueue::createBufferQueue(&bq.producer, &bq.consumer);
+ sp<TestConsumerListener> listener = sp<TestConsumerListener>::make();
+ bq.consumer->consumerConnect(listener, /*controlledByApp*/ true);
+
+ uint64_t id = 0;
+ bq.producer->getUniqueId(&id);
+ std::string name = base::StringPrintf("%s-%" PRIu64, mName, id);
+
+ out->name = String16(name.c_str());
+ out->graphicBufferProducer = bq.producer;
+ mBqs.push_back(std::move(bq));
+
+ return binder::Status::ok();
+ }
+
+ virtual binder::Status killNow() override {
+ ALOGE("LibGUI Test Service %s dying in response to killNow", mName);
+ _exit(0);
+ // Not reached:
+ return binder::Status::ok();
+ }
+
+private:
+ std::mutex mMutex;
+ const char* mName;
+
+ struct BufferQueueHolder {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ };
+
+ std::vector<BufferQueueHolder> mBqs;
+};
+} // namespace
+
+int TestServerMain(const char* name) {
+ ProcessState::self()->startThreadPool();
+
+ sp<TestServiceImpl> testService = sp<TestServiceImpl>::make(name);
+ ALOGE("service");
+ sp<IServiceManager> serviceManager(defaultServiceManager());
+ LOG_ALWAYS_FATAL_IF(OK != serviceManager->addService(String16(name), testService));
+
+ ALOGD("LibGUI Test Service %s STARTED", name);
+
+ IPCThreadState::self()->joinThreadPool();
+
+ ALOGW("LibGUI Test Service %s DIED", name);
+
+ return 0;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/tests/testserver/TestServer.h b/libs/gui/tests/testserver/TestServer.h
new file mode 100644
index 0000000..4226f1b
--- /dev/null
+++ b/libs/gui/tests/testserver/TestServer.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2024 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
+
+namespace android {
+
+/*
+ * Main method for a libgui ITestServer server.
+ *
+ * This must be called without any binder setup having been done, because you can't fork and do
+ * binder things once ProcessState is set up.
+ * @param name The service name of the test server to start.
+ * @return retcode
+ */
+int TestServerMain(const char* name);
+
+} // namespace android
diff --git a/libs/gui/tests/testserver/TestServerClient.cpp b/libs/gui/tests/testserver/TestServerClient.cpp
new file mode 100644
index 0000000..e388074
--- /dev/null
+++ b/libs/gui/tests/testserver/TestServerClient.cpp
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2024 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 <sys/wait.h>
+#include <cerrno>
+#define LOG_TAG "TestServerClient"
+
+#include <android-base/stringprintf.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <libgui_test_server/ITestServer.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <atomic>
+#include <csignal>
+#include <cstdlib>
+#include <mutex>
+#include <string>
+
+#include "TestServerClient.h"
+#include "TestServerCommon.h"
+
+namespace android {
+
+namespace {
+
+std::string GetUniqueServiceName() {
+ static std::atomic<int> uniqueId = 1;
+
+ pid_t pid = getpid();
+ int id = uniqueId++;
+ return base::StringPrintf("Libgui-TestServer-%d-%d", pid, id);
+}
+
+struct RemoteTestServerHostHolder {
+ RemoteTestServerHostHolder(pid_t pid, int sendFd, int recvFd)
+ : mPid(pid), mSendFd(sendFd), mRecvFd(recvFd) {}
+ ~RemoteTestServerHostHolder() {
+ std::lock_guard lock(mMutex);
+
+ kill(mPid, SIGKILL);
+ close(mSendFd);
+ close(mRecvFd);
+ }
+
+ pid_t CreateTestServerOrDie(std::string name) {
+ std::lock_guard lock(mMutex);
+
+ CreateServerRequest request;
+ strlcpy(request.name, name.c_str(), sizeof(request.name) / sizeof(request.name[0]));
+
+ ssize_t bytes = write(mSendFd, &request, sizeof(request));
+ LOG_ALWAYS_FATAL_IF(bytes != sizeof(request));
+
+ CreateServerResponse response;
+ bytes = read(mRecvFd, &response, sizeof(response));
+ LOG_ALWAYS_FATAL_IF(bytes != sizeof(response));
+
+ return response.pid;
+ }
+
+private:
+ std::mutex mMutex;
+
+ pid_t mPid;
+ int mSendFd;
+ int mRecvFd;
+};
+
+std::unique_ptr<RemoteTestServerHostHolder> g_remoteTestServerHostHolder = nullptr;
+
+} // namespace
+
+void TestServerClient::InitializeOrDie(const char* filename) {
+ int sendPipeFds[2];
+ int ret = pipe(sendPipeFds);
+ LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess send pipe");
+
+ int recvPipeFds[2];
+ ret = pipe(recvPipeFds);
+ LOG_ALWAYS_FATAL_IF(ret, "Unable to create subprocess recv pipe");
+
+ pid_t childPid = fork();
+ LOG_ALWAYS_FATAL_IF(childPid < 0, "Unable to fork child process");
+
+ if (childPid == 0) {
+ // We forked!
+ close(sendPipeFds[1]);
+ close(recvPipeFds[0]);
+
+ // We'll be reading from the parent's "send" and writing to the parent's "recv".
+ std::string sendPipe = std::to_string(sendPipeFds[0]);
+ std::string recvPipe = std::to_string(recvPipeFds[1]);
+ char* args[] = {
+ const_cast<char*>(filename),
+ const_cast<char*>("--test-server-host"),
+ const_cast<char*>(sendPipe.c_str()),
+ const_cast<char*>(recvPipe.c_str()),
+ nullptr,
+ };
+
+ ret = execv(filename, args);
+ ALOGE("Failed to exec libguiTestServer. ret=%d errno=%d (%s)", ret, errno, strerror(errno));
+ status_t status = -errno;
+ write(recvPipeFds[1], &status, sizeof(status));
+ _exit(EXIT_FAILURE);
+ }
+
+ close(sendPipeFds[0]);
+ close(recvPipeFds[1]);
+
+ // Check for an OK status that the host started. If so, we're good to go.
+ status_t status;
+ ret = read(recvPipeFds[0], &status, sizeof(status));
+ LOG_ALWAYS_FATAL_IF(ret != sizeof(status), "Unable to read from pipe: %d", ret);
+ LOG_ALWAYS_FATAL_IF(OK != status, "Pipe returned failed status: %d", status);
+
+ g_remoteTestServerHostHolder =
+ std::make_unique<RemoteTestServerHostHolder>(childPid, sendPipeFds[1], recvPipeFds[0]);
+}
+
+sp<TestServerClient> TestServerClient::Create() {
+ std::string serviceName = GetUniqueServiceName();
+
+ pid_t childPid = g_remoteTestServerHostHolder->CreateTestServerOrDie(serviceName);
+ ALOGD("Created child server %s with pid %d", serviceName.c_str(), childPid);
+
+ sp<libgui_test_server::ITestServer> server =
+ waitForService<libgui_test_server::ITestServer>(String16(serviceName.c_str()));
+ LOG_ALWAYS_FATAL_IF(server == nullptr);
+ ALOGD("Created connected to child server %s", serviceName.c_str());
+
+ return sp<TestServerClient>::make(server);
+}
+
+TestServerClient::TestServerClient(const sp<libgui_test_server::ITestServer>& server)
+ : mServer(server) {}
+
+TestServerClient::~TestServerClient() {
+ Kill();
+}
+
+sp<IGraphicBufferProducer> TestServerClient::CreateProducer() {
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mIsAlive) {
+ return nullptr;
+ }
+
+ view::Surface surface;
+ binder::Status status = mServer->createProducer(&surface);
+
+ if (!status.isOk()) {
+ ALOGE("Failed to create remote producer. Error: %s", status.exceptionMessage().c_str());
+ return nullptr;
+ }
+
+ if (!surface.graphicBufferProducer) {
+ ALOGE("Remote producer returned no IGBP.");
+ return nullptr;
+ }
+
+ return surface.graphicBufferProducer;
+}
+
+status_t TestServerClient::Kill() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mIsAlive) {
+ return DEAD_OBJECT;
+ }
+
+ mServer->killNow();
+ mServer = nullptr;
+ mIsAlive = false;
+
+ return OK;
+}
+
+} // namespace android
diff --git a/libs/gui/tests/testserver/TestServerClient.h b/libs/gui/tests/testserver/TestServerClient.h
new file mode 100644
index 0000000..5329634
--- /dev/null
+++ b/libs/gui/tests/testserver/TestServerClient.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2024 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 <libgui_test_server/ITestServer.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+class TestServerClient : public RefBase {
+public:
+ static void InitializeOrDie(const char* filename);
+ static sp<TestServerClient> Create();
+
+ TestServerClient(const sp<libgui_test_server::ITestServer>& server);
+ virtual ~TestServerClient() override;
+
+ sp<IGraphicBufferProducer> CreateProducer();
+ status_t Kill();
+
+private:
+ std::mutex mMutex;
+
+ sp<libgui_test_server::ITestServer> mServer;
+ bool mIsAlive = true;
+};
+
+} // namespace android
diff --git a/libs/gui/tests/testserver/TestServerCommon.h b/libs/gui/tests/testserver/TestServerCommon.h
new file mode 100644
index 0000000..7370f20
--- /dev/null
+++ b/libs/gui/tests/testserver/TestServerCommon.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 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 <fcntl.h>
+
+namespace android {
+
+/*
+ * Test -> TestServerHost Request to create a new ITestServer fork.
+ */
+struct CreateServerRequest {
+ /*
+ * Service name for new ITestServer.
+ */
+ char name[128];
+};
+
+/*
+ * TestServerHost -> Test Response for creating an ITestServer fork.
+ */
+struct CreateServerResponse {
+ /*
+ * pid of new ITestServer.
+ */
+ pid_t pid;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/tests/testserver/TestServerHost.cpp b/libs/gui/tests/testserver/TestServerHost.cpp
new file mode 100644
index 0000000..696c3b9
--- /dev/null
+++ b/libs/gui/tests/testserver/TestServerHost.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TestServerHost"
+
+#include <android-base/unique_fd.h>
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/Status.h>
+#include <gui/BufferQueue.h>
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <libgui_test_server/BnTestServer.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+#include <memory>
+#include <vector>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <cstddef>
+#include <cstdlib>
+
+#include "TestServerCommon.h"
+#include "TestServerHost.h"
+
+namespace android {
+
+namespace {
+
+pid_t ForkTestServer(const char* filename, char* name) {
+ pid_t childPid = fork();
+ LOG_ALWAYS_FATAL_IF(childPid == -1);
+
+ if (childPid != 0) {
+ return childPid;
+ }
+
+ // We forked!
+ const char* test_server_flag = "--test-server";
+ char* args[] = {
+ const_cast<char*>(filename),
+ const_cast<char*>(test_server_flag),
+ name,
+ nullptr,
+ };
+
+ int ret = execv(filename, args);
+ ALOGE("Failed to exec libgui_test as a TestServer. ret=%d errno=%d (%s)", ret, errno,
+ strerror(errno));
+ _exit(EXIT_FAILURE);
+}
+
+} // namespace
+
+int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd,
+ base::unique_fd recvPipeFd) {
+ status_t status = OK;
+ LOG_ALWAYS_FATAL_IF(sizeof(status) != write(sendPipeFd.get(), &status, sizeof(status)));
+
+ ALOGE("Launched TestServerHost");
+
+ while (true) {
+ CreateServerRequest request = {};
+ ssize_t bytes = read(recvPipeFd.get(), &request, sizeof(request));
+ LOG_ALWAYS_FATAL_IF(bytes != sizeof(request));
+ pid_t childPid = ForkTestServer(filename, request.name);
+
+ CreateServerResponse response = {};
+ response.pid = childPid;
+ bytes = write(sendPipeFd.get(), &response, sizeof(response));
+ LOG_ALWAYS_FATAL_IF(bytes != sizeof(response));
+ }
+
+ return 0;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/tests/testserver/TestServerHost.h b/libs/gui/tests/testserver/TestServerHost.h
new file mode 100644
index 0000000..df22c0c
--- /dev/null
+++ b/libs/gui/tests/testserver/TestServerHost.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 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 <android-base/unique_fd.h>
+
+#include <string>
+
+namespace android {
+
+/*
+ * Main method for a host process for TestServers.
+ *
+ * This must be called without any binder setup having been done, because you can't fork and do
+ * binder things once ProcessState is set up.
+ * @param filename File name of this binary / the binary to execve into
+ * @param sendPipeFd Pipe FD to send data to.
+ * @param recvPipeFd Pipe FD to receive data from.
+ * @return retcode
+ */
+int TestServerHostMain(const char* filename, base::unique_fd sendPipeFd,
+ base::unique_fd recvPipeFd);
+
+} // namespace android
diff --git a/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl
new file mode 100644
index 0000000..c939ea0
--- /dev/null
+++ b/libs/gui/tests/testserver/aidl/libgui_test_server/ITestServer.aidl
@@ -0,0 +1,12 @@
+package libgui_test_server;
+
+import android.view.Surface;
+
+// Test server for libgui_test
+interface ITestServer {
+ // Create a new producer. The server will have connected to the consumer.
+ Surface createProducer();
+
+ // Kills the server immediately.
+ void killNow();
+}
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index 7c15e7c..84c2a6a 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -121,5 +121,11 @@
return str.value_or(String16());
}
+std::string Surface::toString() const {
+ std::stringstream out;
+ out << name;
+ return out.str();
+}
+
} // namespace view
} // namespace android
diff --git a/libs/input/Resampler.cpp b/libs/input/Resampler.cpp
index af8354c..342f7f5 100644
--- a/libs/input/Resampler.cpp
+++ b/libs/input/Resampler.cpp
@@ -60,10 +60,10 @@
return a + alpha * (b - a);
}
-const PointerCoords calculateResampledCoords(const PointerCoords& a, const PointerCoords& b,
- const float alpha) {
- // Ensure the struct PointerCoords is initialized.
- PointerCoords resampledCoords{};
+PointerCoords calculateResampledCoords(const PointerCoords& a, const PointerCoords& b,
+ float alpha) {
+ // We use the value of alpha to initialize resampledCoords with the latest sample information.
+ PointerCoords resampledCoords = (alpha < 1.0f) ? a : b;
resampledCoords.isResampled = true;
resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X, lerp(a.getX(), b.getX(), alpha));
resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, lerp(a.getY(), b.getY(), alpha));
@@ -72,52 +72,85 @@
} // namespace
void LegacyResampler::updateLatestSamples(const MotionEvent& motionEvent) {
- const size_t motionEventSampleSize = motionEvent.getHistorySize() + 1;
- for (size_t i = 0; i < motionEventSampleSize; ++i) {
- Sample sample{static_cast<nanoseconds>(motionEvent.getHistoricalEventTime(i)),
- *motionEvent.getPointerProperties(0),
- motionEvent.getSamplePointerCoords()[i]};
- mLatestSamples.pushBack(sample);
+ const size_t numSamples = motionEvent.getHistorySize() + 1;
+ for (size_t i = 0; i < numSamples; ++i) {
+ mLatestSamples.pushBack(
+ Sample{static_cast<nanoseconds>(motionEvent.getHistoricalEventTime(i)),
+ Pointer{*motionEvent.getPointerProperties(0),
+ motionEvent.getSamplePointerCoords()[i]}});
}
}
-void LegacyResampler::interpolate(const nanoseconds resampleTime, MotionEvent& motionEvent,
- const InputMessage& futureSample) const {
- const Sample pastSample = mLatestSamples.back();
+bool LegacyResampler::canInterpolate(const InputMessage& futureSample) const {
+ LOG_IF(FATAL, mLatestSamples.empty())
+ << "Not resampled. mLatestSamples must not be empty to interpolate.";
+
+ const Sample& pastSample = *(mLatestSamples.end() - 1);
const nanoseconds delta =
static_cast<nanoseconds>(futureSample.body.motion.eventTime) - pastSample.eventTime;
if (delta < RESAMPLE_MIN_DELTA) {
LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns.";
- return;
+ return false;
}
+ return true;
+}
+
+std::optional<LegacyResampler::Sample> LegacyResampler::attemptInterpolation(
+ nanoseconds resampleTime, const InputMessage& futureSample) const {
+ if (!canInterpolate(futureSample)) {
+ return std::nullopt;
+ }
+ LOG_IF(FATAL, mLatestSamples.empty())
+ << "Not resampled. mLatestSamples must not be empty to interpolate.";
+
+ const Sample& pastSample = *(mLatestSamples.end() - 1);
+ const nanoseconds delta =
+ static_cast<nanoseconds>(futureSample.body.motion.eventTime) - pastSample.eventTime;
const float alpha =
std::chrono::duration<float, std::milli>(resampleTime - pastSample.eventTime) / delta;
-
const PointerCoords resampledCoords =
calculateResampledCoords(pastSample.pointer.coords,
futureSample.body.motion.pointers[0].coords, alpha);
- motionEvent.addSample(resampleTime.count(), &resampledCoords, motionEvent.getId());
+
+ return Sample{resampleTime, Pointer{pastSample.pointer.properties, resampledCoords}};
}
-void LegacyResampler::extrapolate(const nanoseconds resampleTime, MotionEvent& motionEvent) const {
+bool LegacyResampler::canExtrapolate() const {
if (mLatestSamples.size() < 2) {
- return;
+ LOG_IF(INFO, debugResampling()) << "Not resampled. Not enough data.";
+ return false;
}
- const Sample pastSample = *(mLatestSamples.end() - 2);
- const Sample presentSample = *(mLatestSamples.end() - 1);
- const nanoseconds delta =
- static_cast<nanoseconds>(presentSample.eventTime - pastSample.eventTime);
+
+ const Sample& pastSample = *(mLatestSamples.end() - 2);
+ const Sample& presentSample = *(mLatestSamples.end() - 1);
+
+ const nanoseconds delta = presentSample.eventTime - pastSample.eventTime;
if (delta < RESAMPLE_MIN_DELTA) {
LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too small: " << delta << "ns.";
- return;
+ return false;
} else if (delta > RESAMPLE_MAX_DELTA) {
LOG_IF(INFO, debugResampling()) << "Not resampled. Delta is too large: " << delta << "ns.";
- return;
+ return false;
}
+ return true;
+}
+
+std::optional<LegacyResampler::Sample> LegacyResampler::attemptExtrapolation(
+ nanoseconds resampleTime) const {
+ if (!canExtrapolate()) {
+ return std::nullopt;
+ }
+ LOG_IF(FATAL, mLatestSamples.size() < 2)
+ << "Not resampled. mLatestSamples must have at least two samples to extrapolate.";
+
+ const Sample& pastSample = *(mLatestSamples.end() - 2);
+ const Sample& presentSample = *(mLatestSamples.end() - 1);
+
+ const nanoseconds delta = presentSample.eventTime - pastSample.eventTime;
// The farthest future time to which we can extrapolate. If the given resampleTime exceeds this,
// we use this value as the resample time target.
- const nanoseconds farthestPrediction = static_cast<nanoseconds>(presentSample.eventTime) +
- std::min<nanoseconds>(delta / 2, RESAMPLE_MAX_PREDICTION);
+ const nanoseconds farthestPrediction =
+ presentSample.eventTime + std::min<nanoseconds>(delta / 2, RESAMPLE_MAX_PREDICTION);
const nanoseconds newResampleTime =
(resampleTime > farthestPrediction) ? (farthestPrediction) : (resampleTime);
LOG_IF(INFO, debugResampling() && newResampleTime == farthestPrediction)
@@ -127,25 +160,32 @@
const float alpha =
std::chrono::duration<float, std::milli>(newResampleTime - pastSample.eventTime) /
delta;
-
const PointerCoords resampledCoords =
calculateResampledCoords(pastSample.pointer.coords, presentSample.pointer.coords,
alpha);
- motionEvent.addSample(newResampleTime.count(), &resampledCoords, motionEvent.getId());
+
+ return Sample{newResampleTime, Pointer{presentSample.pointer.properties, resampledCoords}};
}
-void LegacyResampler::resampleMotionEvent(const nanoseconds resampleTime, MotionEvent& motionEvent,
+inline void LegacyResampler::addSampleToMotionEvent(const Sample& sample,
+ MotionEvent& motionEvent) {
+ motionEvent.addSample(sample.eventTime.count(), &sample.pointer.coords, motionEvent.getId());
+}
+
+void LegacyResampler::resampleMotionEvent(nanoseconds resampleTime, MotionEvent& motionEvent,
const InputMessage* futureSample) {
if (mPreviousDeviceId && *mPreviousDeviceId != motionEvent.getDeviceId()) {
mLatestSamples.clear();
}
mPreviousDeviceId = motionEvent.getDeviceId();
+
updateLatestSamples(motionEvent);
- if (futureSample) {
- interpolate(resampleTime, motionEvent, *futureSample);
- } else {
- extrapolate(resampleTime, motionEvent);
+
+ const std::optional<Sample> sample = (futureSample != nullptr)
+ ? (attemptInterpolation(resampleTime, *futureSample))
+ : (attemptExtrapolation(resampleTime));
+ if (sample.has_value()) {
+ addSampleToMotionEvent(*sample, motionEvent);
}
- LOG_IF(INFO, debugResampling()) << "Not resampled. Not enough data.";
}
} // namespace android
diff --git a/libs/input/tests/Resampler_test.cpp b/libs/input/tests/Resampler_test.cpp
index e160ca0..135f8b4 100644
--- a/libs/input/tests/Resampler_test.cpp
+++ b/libs/input/tests/Resampler_test.cpp
@@ -229,6 +229,38 @@
EXPECT_EQ(originalSampleSize, notResampledSampleSize);
}
+TEST_F(ResamplerTest, NonResampledAxesArePreserved) {
+ constexpr float TOUCH_MAJOR_VALUE = 1.0f;
+
+ MotionEvent motionEvent =
+ InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}},
+ AMOTION_EVENT_ACTION_MOVE};
+
+ constexpr std::chrono::nanoseconds eventTime{10ms};
+ PointerCoords pointerCoords{};
+ pointerCoords.isResampled = false;
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, 2.0f);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, 2.0f);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, TOUCH_MAJOR_VALUE);
+
+ motionEvent.addSample(eventTime.count(), &pointerCoords, motionEvent.getId());
+
+ const InputMessage futureSample =
+ InputSample{15ms, {{.id = 0, .x = 3.0f, .y = 4.0f, .isResampled = false}}};
+
+ const MotionEvent originalMotionEvent = motionEvent;
+
+ mResampler->resampleMotionEvent(11ms, motionEvent, &futureSample);
+
+ EXPECT_EQ(motionEvent.getTouchMajor(0), TOUCH_MAJOR_VALUE);
+
+ assertMotionEventIsResampledAndCoordsNear(originalMotionEvent, motionEvent,
+ Pointer{.id = 0,
+ .x = 2.2f,
+ .y = 2.4f,
+ .isResampled = true});
+}
+
TEST_F(ResamplerTest, SinglePointerNotEnoughDataToResample) {
MotionEvent motionEvent =
InputStream{{{5ms, {{.id = 0, .x = 1.0f, .y = 1.0f, .isResampled = false}}}},
diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
index 1dbcc29..4164c4b 100644
--- a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
+++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.cpp
@@ -19,6 +19,7 @@
#include <SkRuntimeEffect.h>
#include <SkStream.h>
#include <SkString.h>
+#include <com_android_graphics_libgui_flags.h>
#include "log/log_main.h"
namespace android::renderengine::skia {
@@ -56,25 +57,33 @@
}
)");
+EdgeExtensionShaderFactory::EdgeExtensionShaderFactory() {
+ if (!com::android::graphics::libgui::flags::edge_extension_shader()) {
+ return;
+ }
+ mResult = std::make_unique<SkRuntimeEffect::Result>(SkRuntimeEffect::MakeForShader(edgeShader));
+ LOG_ALWAYS_FATAL_IF(!mResult->errorText.isEmpty(),
+ "EdgeExtensionShaderFactory compilation "
+ "failed with an unexpected error: %s",
+ mResult->errorText.c_str());
+}
+
sk_sp<SkShader> EdgeExtensionShaderFactory::createSkShader(const sk_sp<SkShader>& inputShader,
const LayerSettings& layer,
- const SkRect& imageBounds) {
- if (mBuilder == nullptr) {
- const static SkRuntimeEffect::Result instance = SkRuntimeEffect::MakeForShader(edgeShader);
- if (!instance.errorText.isEmpty()) {
- ALOGE("EdgeExtensionShaderFactory terminated with an error: %s",
- instance.errorText.c_str());
- return nullptr;
- }
- mBuilder = std::make_unique<SkRuntimeShaderBuilder>(instance.effect);
- }
- mBuilder->child("uContentTexture") = inputShader;
+ const SkRect& imageBounds) const {
+ LOG_ALWAYS_FATAL_IF(mResult == nullptr,
+ "EdgeExtensionShaderFactory did not initialize mResult. "
+ "This means that we unexpectedly applied the edge extension shader");
+
+ SkRuntimeShaderBuilder builder = SkRuntimeShaderBuilder(mResult->effect);
+
+ builder.child("uContentTexture") = inputShader;
if (imageBounds.isEmpty()) {
- mBuilder->uniform("uImgSize") = SkPoint{layer.geometry.boundaries.getWidth(),
- layer.geometry.boundaries.getHeight()};
+ builder.uniform("uImgSize") = SkPoint{layer.geometry.boundaries.getWidth(),
+ layer.geometry.boundaries.getHeight()};
} else {
- mBuilder->uniform("uImgSize") = SkPoint{imageBounds.width(), imageBounds.height()};
+ builder.uniform("uImgSize") = SkPoint{imageBounds.width(), imageBounds.height()};
}
- return mBuilder->makeShader();
+ return builder.makeShader();
}
} // namespace android::renderengine::skia
\ No newline at end of file
diff --git a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h
index b0a8a93..17c6b91 100644
--- a/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h
+++ b/libs/renderengine/skia/filters/EdgeExtensionShaderFactory.h
@@ -33,10 +33,12 @@
*/
class EdgeExtensionShaderFactory {
public:
+ EdgeExtensionShaderFactory();
+
sk_sp<SkShader> createSkShader(const sk_sp<SkShader>& inputShader, const LayerSettings& layer,
- const SkRect& imageBounds);
+ const SkRect& imageBounds) const;
private:
- std::unique_ptr<SkRuntimeShaderBuilder> mBuilder;
+ std::unique_ptr<const SkRuntimeEffect::Result> mResult;
};
} // namespace android::renderengine::skia
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index 5673678..7b4a86c 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -84,7 +84,7 @@
std::ostringstream oss;
oss << sensor.getStringType() << ":" << sensor.getName();
if (outString) {
- *outString = std::move(oss.str());
+ *outString = oss.str();
}
return true;
}
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index 9aae145..a75ba37 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -156,6 +156,6 @@
base::unique_fd mFenceFd;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_FENCE_H
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 652d8ba..936bf8f 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -297,6 +297,6 @@
mDeathCallbacks;
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_GRAPHIC_BUFFER_H
diff --git a/libs/ui/include/ui/GraphicBufferAllocator.h b/libs/ui/include/ui/GraphicBufferAllocator.h
index bbb2d77..97ed05a 100644
--- a/libs/ui/include/ui/GraphicBufferAllocator.h
+++ b/libs/ui/include/ui/GraphicBufferAllocator.h
@@ -137,6 +137,6 @@
};
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_BUFFER_ALLOCATOR_H
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 9da1447..91aabe9 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -188,7 +188,7 @@
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
#endif // ANDROID_UI_BUFFER_MAPPER_H
diff --git a/libs/ui/include/ui/PixelFormat.h b/libs/ui/include/ui/PixelFormat.h
index cf5c2e8..1f20787 100644
--- a/libs/ui/include/ui/PixelFormat.h
+++ b/libs/ui/include/ui/PixelFormat.h
@@ -72,6 +72,6 @@
uint32_t bytesPerPixel(PixelFormat format);
-}; // namespace android
+} // namespace android
#endif // UI_PIXELFORMAT_H
diff --git a/libs/ui/include/ui/Point.h b/libs/ui/include/ui/Point.h
index d050ede..97a54be 100644
--- a/libs/ui/include/ui/Point.h
+++ b/libs/ui/include/ui/Point.h
@@ -83,6 +83,6 @@
ANDROID_BASIC_TYPES_TRAITS(Point)
-}; // namespace android
+} // namespace android
#endif // ANDROID_UI_POINT
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 9e24a07..2eb9330 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -233,7 +233,7 @@
ANDROID_BASIC_TYPES_TRAITS(Rect)
-}; // namespace android
+} // namespace android
namespace std {
template <>
diff --git a/libs/ui/include/ui/Region.h b/libs/ui/include/ui/Region.h
index 927c334..d1b38f3 100644
--- a/libs/ui/include/ui/Region.h
+++ b/libs/ui/include/ui/Region.h
@@ -233,7 +233,7 @@
}
// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
namespace std {
template <>
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 4454f36..37dc931 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -30,6 +30,10 @@
to: "",
srcs: ["include/EGL/**/*.h"],
license: "include/EGL/NOTICE",
+ // eglext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
@@ -38,6 +42,10 @@
to: "",
srcs: ["include/GLES/**/*.h"],
license: "include/GLES/NOTICE",
+ // glext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
@@ -46,6 +54,10 @@
to: "",
srcs: ["include/GLES2/**/*.h"],
license: "include/GLES2/NOTICE",
+ // gl2ext.h is not self-contained. Safe to skip C-compat verification
+ // though since upstream also cares about C compatibility, and the header is
+ // auto-generated anyway.
+ skip_verification: true,
}
ndk_headers {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 0384257..bcef350 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -2713,7 +2713,8 @@
{
std::vector<TouchedWindow> hoveringWindows =
getHoveringWindowsLocked(oldState, tempTouchState, entry,
- [this]() REQUIRES(mLock) { logDispatchStateLocked(); });
+ std::bind_front(&InputDispatcher::logDispatchStateLocked,
+ this));
// Hardcode to single hovering pointer for now.
std::bitset<MAX_POINTER_ID + 1> pointerIds;
pointerIds.set(entry.pointerProperties[0].id);
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index ed4c47d..b4ac9ba 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -149,6 +149,7 @@
"tests/CompositionEngineTest.cpp",
"tests/DisplayColorProfileTest.cpp",
"tests/DisplayTest.cpp",
+ "tests/HwcAsyncWorkerTest.cpp",
"tests/HwcBufferCacheTest.cpp",
"tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
index 6086f0b..91385b4 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcAsyncWorker.cpp
@@ -24,6 +24,7 @@
#include <android-base/thread_annotations.h>
#include <cutils/sched_policy.h>
+#include <ftl/fake_guard.h>
namespace android::compositionengine::impl {
@@ -60,7 +61,7 @@
std::unique_lock<std::mutex> lock(mMutex);
android::base::ScopedLockAssertion assumeLock(mMutex);
while (!mDone) {
- mCv.wait(lock);
+ mCv.wait(lock, [this]() FTL_FAKE_GUARD(mMutex) { return mTaskRequested || mDone; });
if (mTaskRequested && mTask.valid()) {
mTask();
mTaskRequested = false;
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 64cded8..2d8f98f 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1101,10 +1101,10 @@
}
ftl::Future<std::monostate> Output::presentFrameAndReleaseLayersAsync(bool flushEvenWhenDisabled) {
- return ftl::Future<bool>(std::move(mHwComposerAsyncWorker->send([this, flushEvenWhenDisabled]() {
+ return ftl::Future<bool>(mHwComposerAsyncWorker->send([this, flushEvenWhenDisabled]() {
presentFrameAndReleaseLayers(flushEvenWhenDisabled);
return true;
- })))
+ }))
.then([](bool) { return std::monostate{}; });
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcAsyncWorkerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcAsyncWorkerTest.cpp
new file mode 100644
index 0000000..dd04df6
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcAsyncWorkerTest.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2024 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 <future>
+
+#include <compositionengine/impl/HwcAsyncWorker.h>
+#include <gtest/gtest.h>
+
+namespace android::compositionengine {
+namespace {
+
+using namespace std::chrono_literals;
+
+// For the edge case tests below, how much real time should be spent trying to reproduce edge cases
+// problems in a loop.
+//
+// Larger values mean problems are more likely to be detected, at the cost of making the unit test
+// run slower.
+//
+// As we expect the tests to be run continuously, even a short loop will eventually catch
+// problems, though not necessarily from changes in the same build that introduce them.
+constexpr auto kWallTimeForEdgeCaseTests = 5ms;
+
+TEST(HwcAsyncWorker, continuousTasksEdgeCase) {
+ // Ensures that a single worker that is given multiple tasks in short succession will run them.
+
+ impl::HwcAsyncWorker worker;
+ const auto endTime = std::chrono::steady_clock::now() + kWallTimeForEdgeCaseTests;
+ while (std::chrono::steady_clock::now() < endTime) {
+ auto f1 = worker.send([] { return false; });
+ EXPECT_FALSE(f1.get());
+ auto f2 = worker.send([] { return true; });
+ EXPECT_TRUE(f2.get());
+ }
+}
+
+TEST(HwcAsyncWorker, constructAndDestroyEdgeCase) {
+ // Ensures that newly created HwcAsyncWorkers can be immediately destroyed.
+
+ const auto endTime = std::chrono::steady_clock::now() + kWallTimeForEdgeCaseTests;
+ while (std::chrono::steady_clock::now() < endTime) {
+ impl::HwcAsyncWorker worker;
+ }
+}
+
+TEST(HwcAsyncWorker, newlyCreatedRunsTasksEdgeCase) {
+ // Ensures that newly created HwcAsyncWorkers will run a task if given one immediately.
+
+ const auto endTime = std::chrono::steady_clock::now() + kWallTimeForEdgeCaseTests;
+ while (std::chrono::steady_clock::now() < endTime) {
+ impl::HwcAsyncWorker worker;
+ auto f = worker.send([] { return true; });
+ f.get();
+ }
+}
+
+} // namespace
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/Display/DisplayModeController.cpp b/services/surfaceflinger/Display/DisplayModeController.cpp
index c43d585..0e9218c 100644
--- a/services/surfaceflinger/Display/DisplayModeController.cpp
+++ b/services/surfaceflinger/Display/DisplayModeController.cpp
@@ -22,7 +22,9 @@
#include "Display/DisplaySnapshot.h"
#include "DisplayHardware/HWComposer.h"
+#include <android-base/properties.h>
#include <common/FlagManager.h>
+#include <common/trace.h>
#include <ftl/concat.h>
#include <ftl/expected.h>
#include <log/log.h>
@@ -237,4 +239,63 @@
}
}
+void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId) {
+ std::lock_guard lock(mDisplayLock);
+ const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
+
+ const auto controllerOpt = displayPtr->selectorPtr->kernelIdleTimerController();
+ if (!controllerOpt) return;
+
+ using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction;
+
+ switch (displayPtr->selectorPtr->getIdleTimerAction()) {
+ case KernelIdleTimerAction::TurnOff:
+ if (displayPtr->isKernelIdleTimerEnabled) {
+ SFTRACE_INT("KernelIdleTimer", 0);
+ updateKernelIdleTimer(displayId, std::chrono::milliseconds::zero(), *controllerOpt);
+ displayPtr->isKernelIdleTimerEnabled = false;
+ }
+ break;
+ case KernelIdleTimerAction::TurnOn:
+ if (!displayPtr->isKernelIdleTimerEnabled) {
+ SFTRACE_INT("KernelIdleTimer", 1);
+ const auto timeout = displayPtr->selectorPtr->getIdleTimerTimeout();
+ updateKernelIdleTimer(displayId, timeout, *controllerOpt);
+ displayPtr->isKernelIdleTimerEnabled = true;
+ }
+ break;
+ }
+}
+
+void DisplayModeController::updateKernelIdleTimer(PhysicalDisplayId displayId,
+ std::chrono::milliseconds timeout,
+ KernelIdleTimerController controller) {
+ switch (controller) {
+ case KernelIdleTimerController::HwcApi:
+ mComposerPtr->setIdleTimerEnabled(displayId, timeout);
+ break;
+
+ case KernelIdleTimerController::Sysprop:
+ using namespace std::string_literals;
+ base::SetProperty("graphics.display.kernel_idle_timer.enabled"s,
+ timeout > std::chrono::milliseconds::zero() ? "true"s : "false"s);
+ break;
+ }
+}
+
+auto DisplayModeController::getKernelIdleTimerState(PhysicalDisplayId displayId) const
+ -> KernelIdleTimerState {
+ std::lock_guard lock(mDisplayLock);
+ const auto& displayPtr =
+ FTL_EXPECT(mDisplays.get(displayId).ok_or(KernelIdleTimerState())).get();
+
+ const auto desiredModeIdOpt =
+ (std::scoped_lock(displayPtr->desiredModeLock), displayPtr->desiredModeOpt)
+ .transform([](const display::DisplayModeRequest& request) {
+ return request.mode.modePtr->getId();
+ });
+
+ return {desiredModeIdOpt, displayPtr->isKernelIdleTimerEnabled};
+}
+
} // namespace android::display
diff --git a/services/surfaceflinger/Display/DisplayModeController.h b/services/surfaceflinger/Display/DisplayModeController.h
index 258b04b..9ec603d 100644
--- a/services/surfaceflinger/Display/DisplayModeController.h
+++ b/services/surfaceflinger/Display/DisplayModeController.h
@@ -97,6 +97,17 @@
void setActiveMode(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps)
EXCLUDES(mDisplayLock);
+ void updateKernelIdleTimer(PhysicalDisplayId) REQUIRES(kMainThreadContext)
+ EXCLUDES(mDisplayLock);
+
+ struct KernelIdleTimerState {
+ std::optional<DisplayModeId> desiredModeIdOpt = std::nullopt;
+ bool isEnabled = false;
+ };
+
+ KernelIdleTimerState getKernelIdleTimerState(PhysicalDisplayId) const
+ REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
+
private:
struct Display {
template <size_t N>
@@ -121,6 +132,8 @@
DisplayModeRequestOpt pendingModeOpt GUARDED_BY(kMainThreadContext);
bool isModeSetPending GUARDED_BY(kMainThreadContext) = false;
+
+ bool isKernelIdleTimerEnabled GUARDED_BY(kMainThreadContext) = false;
};
using DisplayPtr = std::unique_ptr<Display>;
@@ -128,6 +141,10 @@
void setActiveModeLocked(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps)
REQUIRES(mDisplayLock);
+ using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController;
+ void updateKernelIdleTimer(PhysicalDisplayId, std::chrono::milliseconds timeout,
+ KernelIdleTimerController) REQUIRES(mDisplayLock);
+
// Set once when initializing the DisplayModeController, which the HWComposer must outlive.
HWComposer* mComposerPtr = nullptr;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 75b07a8..402a3d2 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -201,19 +201,6 @@
return mPowerMode != hal::PowerMode::OFF;
}
-nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
- const auto physicalId = getPhysicalId();
- if (!mHwComposer.isConnected(physicalId)) {
- return 0;
- }
-
- if (const auto vsyncPeriodOpt = mHwComposer.getDisplayVsyncPeriod(physicalId).value_opt()) {
- return *vsyncPeriodOpt;
- }
-
- return refreshRateSelector().getActiveMode().modePtr->getVsyncRate().getPeriodNsecs();
-}
-
ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
return mCompositionDisplay->getState().dataspace;
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 1b8a3a8..3e3f558 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -203,8 +203,6 @@
void updateHdrSdrRatioOverlayRatio(float currentHdrSdrRatio);
bool isHdrSdrRatioOverlayEnabled() const { return mHdrSdrRatioOverlay != nullptr; }
- nsecs_t getVsyncPeriodFromHWC() const;
-
Fps getAdjustedRefreshRate() const { return mAdjustedRefreshRate; }
// Round the requested refresh rate to match a divisor of the pacesetter
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index d50a0bc..0eced73 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -44,6 +44,7 @@
using aidl::android::hardware::graphics::composer3::BnComposerCallback;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
+using aidl::android::hardware::graphics::composer3::Lut;
using aidl::android::hardware::graphics::composer3::PowerMode;
using aidl::android::hardware::graphics::composer3::VirtualDisplay;
@@ -1539,6 +1540,18 @@
return error;
}
+Error AidlComposer::getDisplayLuts(Display display, std::vector<Lut>* outLuts) {
+ Error error = Error::NONE;
+ mMutex.lock_shared();
+ if (auto reader = getReader(display)) {
+ *outLuts = reader->get().takeDisplayLuts(translate<int64_t>(display));
+ } else {
+ error = Error::BAD_DISPLAY;
+ }
+ mMutex.unlock_shared();
+ return error;
+}
+
Error AidlComposer::setLayerBrightness(Display display, Layer layer, float brightness) {
Error error = Error::NONE;
mMutex.lock_shared();
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index ea0e53a..3669d4c 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -244,6 +244,9 @@
Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override;
Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime,
int32_t frameIntervalNs) override;
+ Error getDisplayLuts(
+ Display display,
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) override;
private:
// Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index bc067a0..888dc08 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -41,6 +41,7 @@
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h>
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
+#include <aidl/android/hardware/graphics/composer3/Lut.h>
#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
#include <aidl/android/hardware/graphics/common/Transform.h>
@@ -303,6 +304,7 @@
virtual Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) = 0;
virtual Error notifyExpectedPresent(Display, nsecs_t expectedPresentTime,
int32_t frameIntervalNs) = 0;
+ virtual Error getDisplayLuts(Display display, std::vector<V3_0::Lut>* outLuts) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 8c0f81e..d5f65c6 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -41,6 +41,7 @@
using aidl::android::hardware::graphics::composer3::Composition;
using AidlCapability = aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using aidl::android::hardware::graphics::composer3::Lut;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
namespace android {
@@ -607,6 +608,18 @@
return static_cast<Error>(error);
}
+Error Display::getDisplayLuts(std::vector<Lut>* outLuts) {
+ std::vector<Lut> tmpLuts;
+ const auto error = mComposer.getDisplayLuts(mId, &tmpLuts);
+ for (Lut& lut : tmpLuts) {
+ if (lut.pfd.get() >= 0) {
+ outLuts->push_back(
+ {lut.layer, ndk::ScopedFileDescriptor(lut.pfd.release()), lut.lutProperties});
+ }
+ }
+ return static_cast<Error>(error);
+}
+
Error Display::getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 5b94831..be2059a 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -45,6 +45,7 @@
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
+#include <aidl/android/hardware/graphics/composer3/Lut.h>
#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
#include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h>
@@ -178,6 +179,8 @@
[[nodiscard]] virtual hal::Error getClientTargetProperty(
aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
outClientTargetProperty) = 0;
+ [[nodiscard]] virtual hal::Error getDisplayLuts(
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) = 0;
[[nodiscard]] virtual hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) = 0;
@@ -261,6 +264,8 @@
hal::Error getClientTargetProperty(
aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness*
outClientTargetProperty) override;
+ hal::Error getDisplayLuts(
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>* outLuts) override;
hal::Error getDisplayDecorationSupport(
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
support) override;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 7c4aa75..ec2a3ec 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -46,6 +46,7 @@
using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using aidl::android::hardware::graphics::composer3::DimmingStage;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
+using aidl::android::hardware::graphics::composer3::Lut;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
namespace android {
@@ -1408,6 +1409,10 @@
return Error::NONE;
}
+Error HidlComposer::getDisplayLuts(Display, std::vector<Lut>*) {
+ return Error::NONE;
+}
+
Error HidlComposer::setLayerBrightness(Display, Layer, float) {
return Error::NONE;
}
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index d78bfb7..8bca5ad 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -351,6 +351,8 @@
Hdr*) override;
Error setRefreshRateChangedCallbackDebugEnabled(Display, bool) override;
Error notifyExpectedPresent(Display, nsecs_t, int32_t) override;
+ Error getDisplayLuts(Display,
+ std::vector<aidl::android::hardware::graphics::composer3::Lut>*) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 47fd700..c874db3 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -561,6 +561,7 @@
updateSnapshot(*snapshot, args, *layer, parentSnapshot, traversalPath);
}
+ bool childHasValidFrameRate = false;
for (auto& [childHierarchy, variant] : hierarchy.mChildren) {
LayerHierarchy::ScopedAddToTraversalPath addChildToPath(traversalPath,
childHierarchy->getLayer()->id,
@@ -568,7 +569,8 @@
const LayerSnapshot& childSnapshot =
updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot,
depth + 1);
- updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, args);
+ updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, *childHierarchy->getLayer(),
+ args, &childHasValidFrameRate);
}
return *snapshot;
@@ -675,9 +677,10 @@
}
}
-void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot,
- const LayerSnapshot& childSnapshot,
- const Args& args) {
+void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(
+ LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot,
+ const RequestedLayerState& /* requestedChildState */, const Args& args,
+ bool* outChildHasValidFrameRate) {
if (args.forceUpdate == ForceUpdateFlags::NONE &&
!args.layerLifecycleManager.getGlobalChanges().any(
RequestedLayerState::Changes::Hierarchy) &&
@@ -687,7 +690,7 @@
}
using FrameRateCompatibility = scheduler::FrameRateCompatibility;
- if (snapshot.frameRate.isValid()) {
+ if (snapshot.inheritedFrameRate.isValid() || *outChildHasValidFrameRate) {
// we already have a valid framerate.
return;
}
@@ -704,13 +707,18 @@
const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.vote.rate.isValid() &&
childSnapshot.frameRate.vote.type == FrameRateCompatibility::Exact;
- bool childHasValidFrameRate = layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
+ *outChildHasValidFrameRate |= layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
layerVotedWithCategory || layerVotedWithExactCompatibility;
// If we don't have a valid frame rate, but the children do, we set this
// layer as NoVote to allow the children to control the refresh rate
- if (childHasValidFrameRate) {
- snapshot.frameRate = scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
+ static const auto noVote =
+ scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
+ if (*outChildHasValidFrameRate) {
+ snapshot.frameRate = noVote;
+ snapshot.changes |= RequestedLayerState::Changes::FrameRate;
+ } else if (snapshot.frameRate != snapshot.inheritedFrameRate) {
+ snapshot.frameRate = snapshot.inheritedFrameRate;
snapshot.changes |= RequestedLayerState::Changes::FrameRate;
}
}
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index f3c56a4..207e23a 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -130,7 +130,9 @@
const RequestedLayerState& layer,
const LayerSnapshot& parentSnapshot);
void updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot,
- const LayerSnapshot& childSnapshot, const Args& args);
+ const LayerSnapshot& childSnapshot,
+ const RequestedLayerState& requestedCHildState,
+ const Args& args, bool* outChildHasValidFrameRate);
void updateTouchableRegionCrop(const Args& args);
std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1258509..abdf92c 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -316,7 +316,7 @@
void Layer::addToCurrentState() {
if (mRemovedFromDrawingState) {
mRemovedFromDrawingState = false;
- mFlinger->mScheduler->registerLayer(this);
+ mFlinger->mScheduler->registerLayer(this, FrameRateCompatibility::Default);
mFlinger->removeFromOffscreenLayers(this);
}
@@ -1100,42 +1100,6 @@
return true;
}
-bool Layer::setFrameRateSelectionPriority(int32_t priority) {
- if (mDrawingState.frameRateSelectionPriority == priority) return false;
- mDrawingState.frameRateSelectionPriority = priority;
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-int32_t Layer::getFrameRateSelectionPriority() const {
- // Check if layer has priority set.
- if (mDrawingState.frameRateSelectionPriority != PRIORITY_UNSET) {
- return mDrawingState.frameRateSelectionPriority;
- }
- // If not, search whether its parents have it set.
- sp<Layer> parent = getParent();
- if (parent != nullptr) {
- return parent->getFrameRateSelectionPriority();
- }
-
- return Layer::PRIORITY_UNSET;
-}
-
-bool Layer::setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility) {
- if (mDrawingState.defaultFrameRateCompatibility == compatibility) return false;
- mDrawingState.defaultFrameRateCompatibility = compatibility;
- mDrawingState.modified = true;
- mFlinger->mScheduler->setDefaultFrameRateCompatibility(sequence, compatibility);
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-scheduler::FrameRateCompatibility Layer::getDefaultFrameRateCompatibility() const {
- return mDrawingState.defaultFrameRateCompatibility;
-}
-
bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) {
return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
};
@@ -1202,117 +1166,6 @@
return StretchEffect{};
}
-bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overrideChildren,
- bool* transactionNeeded) {
- // Gets the frame rate to propagate to children.
- const auto frameRate = [&] {
- if (overrideChildren && parentFrameRate.isValid()) {
- return parentFrameRate;
- }
-
- if (mDrawingState.frameRate.isValid()) {
- return mDrawingState.frameRate;
- }
-
- return parentFrameRate;
- }();
-
- auto now = systemTime();
- *transactionNeeded |= setFrameRateForLayerTreeLegacy(frameRate, now);
-
- // The frame rate is propagated to the children by default, but some properties may override it.
- bool childrenHaveFrameRate = false;
- const bool overrideChildrenFrameRate = overrideChildren || shouldOverrideChildrenFrameRate();
- const bool canPropagateFrameRate = shouldPropagateFrameRate() || overrideChildrenFrameRate;
- for (const sp<Layer>& child : mCurrentChildren) {
- childrenHaveFrameRate |=
- child->propagateFrameRateForLayerTree(canPropagateFrameRate ? frameRate
- : FrameRate(),
- overrideChildrenFrameRate, transactionNeeded);
- }
-
- // If we don't have a valid frame rate specification, but the children do, we set this
- // layer as NoVote to allow the children to control the refresh rate
- if (!frameRate.isValid() && childrenHaveFrameRate) {
- *transactionNeeded |=
- setFrameRateForLayerTreeLegacy(FrameRate(Fps(), FrameRateCompatibility::NoVote),
- now);
- }
-
- // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes for
- // the same reason we are allowing touch boost for those layers. See
- // RefreshRateSelector::rankFrameRates for details.
- const auto layerVotedWithDefaultCompatibility =
- frameRate.vote.rate.isValid() && frameRate.vote.type == FrameRateCompatibility::Default;
- const auto layerVotedWithNoVote = frameRate.vote.type == FrameRateCompatibility::NoVote;
- const auto layerVotedWithCategory = frameRate.category != FrameRateCategory::Default;
- const auto layerVotedWithExactCompatibility =
- frameRate.vote.rate.isValid() && frameRate.vote.type == FrameRateCompatibility::Exact;
- return layerVotedWithDefaultCompatibility || layerVotedWithNoVote || layerVotedWithCategory ||
- layerVotedWithExactCompatibility || childrenHaveFrameRate;
-}
-
-void Layer::updateTreeHasFrameRateVote() {
- const auto root = [&]() -> sp<Layer> {
- sp<Layer> layer = sp<Layer>::fromExisting(this);
- while (auto parent = layer->getParent()) {
- layer = parent;
- }
- return layer;
- }();
-
- bool transactionNeeded = false;
- root->propagateFrameRateForLayerTree({}, false, &transactionNeeded);
-
- // TODO(b/195668952): we probably don't need eTraversalNeeded here
- if (transactionNeeded) {
- mFlinger->setTransactionFlags(eTraversalNeeded);
- }
-}
-
-bool Layer::setFrameRate(FrameRate::FrameRateVote frameRateVote) {
- if (mDrawingState.frameRate.vote == frameRateVote) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.frameRate.vote = frameRateVote;
- mDrawingState.modified = true;
-
- updateTreeHasFrameRateVote();
-
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setFrameRateCategory(FrameRateCategory category, bool smoothSwitchOnly) {
- if (mDrawingState.frameRate.category == category &&
- mDrawingState.frameRate.categorySmoothSwitchOnly == smoothSwitchOnly) {
- return false;
- }
-
- mDrawingState.sequence++;
- mDrawingState.frameRate.category = category;
- mDrawingState.frameRate.categorySmoothSwitchOnly = smoothSwitchOnly;
- mDrawingState.modified = true;
-
- updateTreeHasFrameRateVote();
-
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
-bool Layer::setFrameRateSelectionStrategy(FrameRateSelectionStrategy strategy) {
- if (mDrawingState.frameRateSelectionStrategy == strategy) return false;
- mDrawingState.frameRateSelectionStrategy = strategy;
- mDrawingState.sequence++;
- mDrawingState.modified = true;
-
- updateTreeHasFrameRateVote();
- setTransactionFlags(eTransactionNeeded);
- return true;
-}
-
void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
nsecs_t postTime, gui::GameMode gameMode) {
mDrawingState.postTime = postTime;
@@ -1446,25 +1299,6 @@
addSurfaceFrameDroppedForBuffer(surfaceFrame, postTime);
}
-bool Layer::setFrameRateForLayerTreeLegacy(FrameRate frameRate, nsecs_t now) {
- if (mDrawingState.frameRateForLayerTree == frameRate) {
- return false;
- }
-
- mDrawingState.frameRateForLayerTree = frameRate;
-
- // TODO(b/195668952): we probably don't need to dirty visible regions here
- // or even store frameRateForLayerTree in mDrawingState
- mDrawingState.sequence++;
- mDrawingState.modified = true;
- setTransactionFlags(eTransactionNeeded);
-
- mFlinger->mScheduler
- ->recordLayerHistory(sequence, getLayerProps(), now, now,
- scheduler::LayerHistory::LayerUpdateType::SetFrameRate);
- return true;
-}
-
bool Layer::setFrameRateForLayerTree(FrameRate frameRate, const scheduler::LayerProps& layerProps,
nsecs_t now) {
if (mDrawingState.frameRateForLayerTree == frameRate) {
@@ -1543,57 +1377,6 @@
result.append("\n");
}
-void Layer::miniDumpLegacy(std::string& result, const DisplayDevice& display) const {
- const auto outputLayer = findOutputLayerForDisplay(&display);
- if (!outputLayer) {
- return;
- }
-
- std::string name;
- if (mName.length() > 77) {
- std::string shortened;
- shortened.append(mName, 0, 36);
- shortened.append("[...]");
- shortened.append(mName, mName.length() - 36);
- name = std::move(shortened);
- } else {
- name = mName;
- }
-
- StringAppendF(&result, " %s\n", name.c_str());
-
- const State& layerState(getDrawingState());
- const auto& outputLayerState = outputLayer->getState();
-
- if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
- StringAppendF(&result, " rel %6d | ", layerState.z);
- } else {
- StringAppendF(&result, " %10d | ", layerState.z);
- }
- StringAppendF(&result, " %10d | ", mWindowType);
- StringAppendF(&result, "%10s | ", toString(getCompositionType(display)).c_str());
- StringAppendF(&result, "%10s | ", toString(outputLayerState.bufferTransform).c_str());
- const Rect& frame = outputLayerState.displayFrame;
- StringAppendF(&result, "%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
- const FloatRect& crop = outputLayerState.sourceCrop;
- StringAppendF(&result, "%6.1f %6.1f %6.1f %6.1f | ", crop.left, crop.top, crop.right,
- crop.bottom);
- const auto frameRate = getFrameRateForLayerTree();
- if (frameRate.vote.rate.isValid() || frameRate.vote.type != FrameRateCompatibility::Default) {
- StringAppendF(&result, "%s %15s %17s", to_string(frameRate.vote.rate).c_str(),
- ftl::enum_string(frameRate.vote.type).c_str(),
- ftl::enum_string(frameRate.vote.seamlessness).c_str());
- } else {
- result.append(41, ' ');
- }
-
- const auto focused = isLayerFocusedBasedOnPriority(getFrameRateSelectionPriority());
- StringAppendF(&result, " [%s]\n", focused ? "*" : " ");
-
- result.append(kDumpTableRowLength, '-');
- result.append("\n");
-}
-
void Layer::miniDump(std::string& result, const frontend::LayerSnapshot& snapshot,
const DisplayDevice& display) const {
const auto outputLayer = findOutputLayerForDisplay(&display, snapshot.path);
@@ -1679,7 +1462,6 @@
mCurrentChildren.add(layer);
layer->setParent(sp<Layer>::fromExisting(this));
- updateTreeHasFrameRateVote();
}
ssize_t Layer::removeChild(const sp<Layer>& layer) {
@@ -1689,9 +1471,6 @@
layer->setParent(nullptr);
const auto removeResult = mCurrentChildren.remove(layer);
- updateTreeHasFrameRateVote();
- layer->updateTreeHasFrameRateVote();
-
return removeResult;
}
@@ -4013,7 +3792,8 @@
}
if (display) {
- const Fps refreshRate = display->refreshRateSelector().getActiveMode().fps;
+ const auto activeMode = display->refreshRateSelector().getActiveMode();
+ const Fps refreshRate = activeMode.fps;
const std::optional<Fps> renderRate =
mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
@@ -4033,7 +3813,12 @@
mFlinger->getHwComposer().getPresentTimestamp(*displayId);
const nsecs_t now = systemTime(CLOCK_MONOTONIC);
- const nsecs_t vsyncPeriod = display->getVsyncPeriodFromHWC();
+ const nsecs_t vsyncPeriod =
+ mFlinger->getHwComposer()
+ .getDisplayVsyncPeriod(*displayId)
+ .value_opt()
+ .value_or(activeMode.modePtr->getVsyncRate().getPeriodNsecs());
+
const nsecs_t actualPresentTime = now - ((now - presentTimestamp) % vsyncPeriod);
mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index c838b97..948c62d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -330,18 +330,10 @@
REQUIRES(mFlinger->mStateLock);
virtual bool setColorSpaceAgnostic(const bool agnostic);
virtual bool setDimmingEnabled(const bool dimmingEnabled);
- virtual bool setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility);
- virtual bool setFrameRateSelectionPriority(int32_t priority);
virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
void setAutoRefresh(bool /* autoRefresh */);
bool setDropInputMode(gui::DropInputMode);
- // If the variable is not set on the layer, it traverses up the tree to inherit the frame
- // rate priority from its parent.
- virtual int32_t getFrameRateSelectionPriority() const;
- //
- virtual FrameRateCompatibility getDefaultFrameRateCompatibility() const;
- //
ui::Dataspace getDataSpace() const;
virtual bool isFrontBuffered() const;
@@ -702,7 +694,6 @@
inline const State& getDrawingState() const { return mDrawingState; }
inline State& getDrawingState() { return mDrawingState; }
- void miniDumpLegacy(std::string& result, const DisplayDevice&) const;
void miniDump(std::string& result, const frontend::LayerSnapshot&, const DisplayDevice&) const;
void dumpFrameStats(std::string& result) const;
void dumpOffscreenDebugInfo(std::string& result) const;
@@ -789,11 +780,6 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
- bool setFrameRate(FrameRate::FrameRateVote);
- bool setFrameRateCategory(FrameRateCategory, bool smoothSwitchOnly);
-
- bool setFrameRateSelectionStrategy(FrameRateSelectionStrategy);
-
virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime,
gui::GameMode gameMode);
@@ -905,19 +891,9 @@
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
const sp<Fence>& releaseFence);
- bool setFrameRateForLayerTreeLegacy(FrameRate, nsecs_t now);
bool setFrameRateForLayerTree(FrameRate, const scheduler::LayerProps&, nsecs_t now);
void recordLayerHistoryBufferUpdate(const scheduler::LayerProps&, nsecs_t now);
void recordLayerHistoryAnimationTx(const scheduler::LayerProps&, nsecs_t now);
- auto getLayerProps() const {
- return scheduler::LayerProps{.visible = isVisible(),
- .bounds = getBounds(),
- .transform = getTransform(),
- .setFrameRateVote = getFrameRateForLayerTree(),
- .frameRateSelectionPriority = getFrameRateSelectionPriority(),
- .isSmallDirty = mSmallDirty,
- .isFrontBuffered = isFrontBuffered()};
- };
bool hasBuffer() const { return mBufferInfo.mBuffer != nullptr; }
void setTransformHint(std::optional<ui::Transform::RotationFlags> transformHint) {
mTransformHint = transformHint;
@@ -1128,7 +1104,6 @@
LayerVector makeChildrenTraversalList(LayerVector::StateSet,
const std::vector<Layer*>& layersInTree);
- void updateTreeHasFrameRateVote();
bool propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool overrideChildren,
bool* transactionNeeded);
void setZOrderRelativeOf(const wp<Layer>& relativeOf);
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 4fd4c0e..64b85c0 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -109,12 +109,12 @@
LayerHistory::~LayerHistory() = default;
-void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled) {
+void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled,
+ FrameRateCompatibility frameRateCompatibility) {
std::lock_guard lock(mLock);
LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound,
"%s already registered", layer->getName().c_str());
- LayerVoteType type =
- getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled);
+ LayerVoteType type = getVoteType(frameRateCompatibility, contentDetectionEnabled);
auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
// The layer can be placed on either map, it is assumed that partitionLayers() will be called
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index c09f148..e3babba 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -51,7 +51,8 @@
~LayerHistory();
// Layers are unregistered when the weak reference expires.
- void registerLayer(Layer*, bool contentDetectionEnabled);
+ void registerLayer(Layer*, bool contentDetectionEnabled,
+ FrameRateCompatibility frameRateCompatibility);
// Sets the display size. Client is responsible for synchronization.
void setDisplayArea(uint32_t displayArea) { mDisplayArea = displayArea; }
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6b31135..727541e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -664,11 +664,12 @@
}
}
-void Scheduler::registerLayer(Layer* layer) {
+void Scheduler::registerLayer(Layer* layer, FrameRateCompatibility frameRateCompatibility) {
// If the content detection feature is off, we still keep the layer history,
// since we use it for other features (like Frame Rate API), so layers
// still need to be registered.
- mLayerHistory.registerLayer(layer, mFeatures.test(Feature::kContentDetection));
+ mLayerHistory.registerLayer(layer, mFeatures.test(Feature::kContentDetection),
+ frameRateCompatibility);
}
void Scheduler::deregisterLayer(Layer* layer) {
@@ -876,22 +877,19 @@
mRefreshRateStats->dump(dumper.out());
dumper.eol();
- {
- utils::Dumper::Section section(dumper, "Frame Targeting"sv);
+ std::scoped_lock lock(mDisplayLock);
+ ftl::FakeGuard guard(kMainThreadContext);
- std::scoped_lock lock(mDisplayLock);
- ftl::FakeGuard guard(kMainThreadContext);
+ for (const auto& [id, display] : mDisplays) {
+ utils::Dumper::Section
+ section(dumper,
+ id == mPacesetterDisplayId
+ ? ftl::Concat("Pacesetter Display ", id.value).c_str()
+ : ftl::Concat("Follower Display ", id.value).c_str());
- for (const auto& [id, display] : mDisplays) {
- utils::Dumper::Section
- section(dumper,
- id == mPacesetterDisplayId
- ? ftl::Concat("Pacesetter Display ", id.value).c_str()
- : ftl::Concat("Follower Display ", id.value).c_str());
-
- display.targeterPtr->dump(dumper);
- dumper.eol();
- }
+ display.selectorPtr->dump(dumper);
+ display.targeterPtr->dump(dumper);
+ dumper.eol();
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 4003d9f..9b32fa9 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -220,7 +220,7 @@
REQUIRES(kMainThreadContext);
// Layers are registered on creation, and unregistered when the weak reference expires.
- void registerLayer(Layer*);
+ void registerLayer(Layer*, FrameRateCompatibility);
void recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime,
nsecs_t now, LayerHistory::LayerUpdateType) EXCLUDES(mDisplayLock);
void setModeChangePending(bool pending);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9633cc5..9be9fee 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -205,8 +205,6 @@
using ui::DisplayPrimaries;
using ui::RenderIntent;
-using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController;
-
namespace hal = android::hardware::graphics::composer::hal;
namespace {
@@ -374,8 +372,6 @@
const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW");
const String16 sWakeupSurfaceFlinger("android.permission.WAKEUP_SURFACE_FLINGER");
-const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
-
// ---------------------------------------------------------------------------
int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
bool SurfaceFlinger::useHwcForRgbToYuv;
@@ -2187,14 +2183,6 @@
static_cast<void>(mScheduler->schedule([this] { sample(); }));
}
-nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
- if (const auto display = getDefaultDisplayDeviceLocked()) {
- return display->getVsyncPeriodFromHWC();
- }
-
- return 0;
-}
-
void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
if (FlagManager::getInstance().connected_display() && timestamp < 0 &&
@@ -5724,7 +5712,7 @@
}
void SurfaceFlinger::dumpStats(const DumpArgs& args, std::string& result) const {
- StringAppendF(&result, "%" PRId64 "\n", getVsyncPeriodFromHWC());
+ StringAppendF(&result, "%" PRId64 "\n", mScheduler->getPacesetterVsyncPeriod().ns());
if (args.size() < 2) return;
const auto name = String8(args[1]);
@@ -5784,11 +5772,6 @@
// TODO(b/241285876): Move to DisplayModeController.
dumper.dump("debugDisplayModeSetByBackdoor"sv, mDebugDisplayModeSetByBackdoor);
dumper.eol();
-
- StringAppendF(&result,
- " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64
- " ns\n\n",
- dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
}
void SurfaceFlinger::dumpEvents(std::string& result) const {
@@ -6945,7 +6928,7 @@
// Update the overlay on the main thread to avoid race conditions with
// RefreshRateSelector::getActiveMode
- static_cast<void>(mScheduler->schedule([=, this] {
+ static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) {
const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked());
if (!display) {
ALOGW("%s: default display is null", __func__);
@@ -6953,15 +6936,9 @@
}
if (!display->isRefreshRateOverlayEnabled()) return;
- const auto desiredModeIdOpt =
- mDisplayModeController.getDesiredMode(display->getPhysicalId())
- .transform([](const display::DisplayModeRequest& request) {
- return request.mode.modePtr->getId();
- });
+ const auto state = mDisplayModeController.getKernelIdleTimerState(display->getPhysicalId());
- const bool timerExpired = mKernelIdleTimerEnabled && expired;
-
- if (display->onKernelTimerChanged(desiredModeIdOpt, timerExpired)) {
+ if (display->onKernelTimerChanged(state.desiredModeIdOpt, state.isEnabled && expired)) {
mScheduler->scheduleFrame();
}
}));
@@ -6983,8 +6960,8 @@
}));
}
-std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds>
-SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId) {
+auto SurfaceFlinger::getKernelIdleTimerProperties(PhysicalDisplayId displayId)
+ -> std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds> {
const bool isKernelIdleTimerHwcSupported = getHwComposer().getComposer()->isSupported(
android::Hwc2::Composer::OptionalFeature::KernelIdleTimer);
const auto timeout = getIdleTimerTimeout(displayId);
@@ -7008,63 +6985,6 @@
return {std::nullopt, timeout};
}
-void SurfaceFlinger::updateKernelIdleTimer(std::chrono::milliseconds timeout,
- KernelIdleTimerController controller,
- PhysicalDisplayId displayId) {
- switch (controller) {
- case KernelIdleTimerController::HwcApi: {
- getHwComposer().setIdleTimerEnabled(displayId, timeout);
- break;
- }
- case KernelIdleTimerController::Sysprop: {
- base::SetProperty(KERNEL_IDLE_TIMER_PROP, timeout > 0ms ? "true" : "false");
- break;
- }
- }
-}
-
-void SurfaceFlinger::toggleKernelIdleTimer() {
- using KernelIdleTimerAction = scheduler::RefreshRateSelector::KernelIdleTimerAction;
-
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display) {
- ALOGW("%s: default display is null", __func__);
- return;
- }
-
- // If the support for kernel idle timer is disabled for the active display,
- // don't do anything.
- const std::optional<KernelIdleTimerController> kernelIdleTimerController =
- display->refreshRateSelector().kernelIdleTimerController();
- if (!kernelIdleTimerController.has_value()) {
- return;
- }
-
- const KernelIdleTimerAction action = display->refreshRateSelector().getIdleTimerAction();
-
- switch (action) {
- case KernelIdleTimerAction::TurnOff:
- if (mKernelIdleTimerEnabled) {
- SFTRACE_INT("KernelIdleTimer", 0);
- std::chrono::milliseconds constexpr kTimerDisabledTimeout = 0ms;
- updateKernelIdleTimer(kTimerDisabledTimeout, kernelIdleTimerController.value(),
- display->getPhysicalId());
- mKernelIdleTimerEnabled = false;
- }
- break;
- case KernelIdleTimerAction::TurnOn:
- if (!mKernelIdleTimerEnabled) {
- SFTRACE_INT("KernelIdleTimer", 1);
- const std::chrono::milliseconds timeout =
- display->refreshRateSelector().getIdleTimerTimeout();
- updateKernelIdleTimer(timeout, kernelIdleTimerController.value(),
- display->getPhysicalId());
- mKernelIdleTimerEnabled = true;
- }
- break;
- }
-}
-
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
@@ -7951,7 +7871,7 @@
if (const bool isPacesetter =
mScheduler->onDisplayModeChanged(displayId, selector.getActiveMode())) {
- toggleKernelIdleTimer();
+ mDisplayModeController.updateKernelIdleTimer(displayId);
}
auto preferredModeOpt = getPreferredDisplayMode(displayId, currentPolicy.defaultMode);
@@ -8068,7 +7988,7 @@
void SurfaceFlinger::onLayerFirstRef(Layer* layer) {
mNumLayers++;
if (!layer->isRemovedFromCurrentState()) {
- mScheduler->registerLayer(layer);
+ mScheduler->registerLayer(layer, scheduler::FrameRateCompatibility::Default);
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8b71f3b..651f2d3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -707,22 +707,13 @@
// ICEPowerCallback overrides:
void notifyCpuLoadUp() override;
- // Toggles the kernel idle timer on or off depending the policy decisions around refresh rates.
- void toggleKernelIdleTimer() REQUIRES(mStateLock);
-
using KernelIdleTimerController = scheduler::RefreshRateSelector::KernelIdleTimerController;
// Get the controller and timeout that will help decide how the kernel idle timer will be
// configured and what value to use as the timeout.
std::pair<std::optional<KernelIdleTimerController>, std::chrono::milliseconds>
getKernelIdleTimerProperties(PhysicalDisplayId) REQUIRES(mStateLock);
- // Updates the kernel idle timer either through HWC or through sysprop
- // depending on which controller is provided
- void updateKernelIdleTimer(std::chrono::milliseconds timeoutMs, KernelIdleTimerController,
- PhysicalDisplayId) REQUIRES(mStateLock);
- // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
- // make calls to sys prop each time.
- bool mKernelIdleTimerEnabled = false;
+
// Show spinner with refresh rate overlay
bool mRefreshRateOverlaySpinner = false;
// Show render rate with refresh rate overlay
@@ -1068,11 +1059,6 @@
REQUIRES(mStateLock, kMainThreadContext);
/*
- * VSYNC
- */
- nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
-
- /*
* Display identification
*/
sp<display::DisplayToken> getPhysicalDisplayTokenLocked(PhysicalDisplayId displayId) const
diff --git a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
index 8b9d14b..3104dd4 100644
--- a/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
+++ b/services/surfaceflinger/tests/common/LayerLifecycleManagerHelper.h
@@ -25,6 +25,7 @@
#include <FrontEnd/LayerHierarchy.h>
#include <FrontEnd/LayerLifecycleManager.h>
#include <FrontEnd/LayerSnapshotBuilder.h>
+#include <Layer.h> // needed for framerate
namespace android::surfaceflinger::frontend {
@@ -84,6 +85,15 @@
mLifecycleManager.addLayers(std::move(layers));
}
+ void createRootLayerWithUid(uint32_t id, gui::Uid uid) {
+ std::vector<std::unique_ptr<RequestedLayerState>> layers;
+ auto args = createArgs(/*id=*/id, /*canBeRoot=*/true, /*parent=*/UNASSIGNED_LAYER_ID,
+ /*mirror=*/UNASSIGNED_LAYER_ID);
+ args.ownerUid = uid.val();
+ layers.emplace_back(std::make_unique<RequestedLayerState>(args));
+ mLifecycleManager.addLayers(std::move(layers));
+ }
+
void createDisplayMirrorLayer(uint32_t id, ui::LayerStack layerStack) {
std::vector<std::unique_ptr<RequestedLayerState>> layers;
layers.emplace_back(std::make_unique<RequestedLayerState>(
@@ -321,6 +331,19 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setFrameRate(uint32_t id, Layer::FrameRate framerate) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.frameRate = framerate.vote.rate.getValue();
+ transactions.back().states.front().state.frameRateCompatibility = 0;
+ transactions.back().states.front().state.changeFrameRateStrategy = 0;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
void setFrameRateCategory(uint32_t id, int8_t frameRateCategory) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
@@ -393,6 +416,14 @@
GRALLOC_USAGE_PROTECTED /*usage*/));
}
+ void setFrontBuffer(uint32_t id) {
+ static uint64_t sBufferId = 1;
+ setBuffer(id,
+ std::make_shared<renderengine::mock::FakeExternalTexture>(
+ 1U /*width*/, 1U /*height*/, sBufferId++, HAL_PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_PROTECTED | AHARDWAREBUFFER_USAGE_FRONT_BUFFER /*usage*/));
+ }
+
void setBufferCrop(uint32_t id, const Rect& bufferCrop) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index d9d239d..f1bd87c 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -80,13 +80,10 @@
"FpsTest.cpp",
"FramebufferSurfaceTest.cpp",
"FrameRateOverrideMappingsTest.cpp",
- "FrameRateSelectionPriorityTest.cpp",
- "FrameRateSelectionStrategyTest.cpp",
"FrameTimelineTest.cpp",
"HWComposerTest.cpp",
"JankTrackerTest.cpp",
"OneShotTimerTest.cpp",
- "LayerHistoryTest.cpp",
"LayerHistoryIntegrationTest.cpp",
"LayerInfoTest.cpp",
"LayerMetadataTest.cpp",
@@ -116,7 +113,6 @@
"SurfaceFlinger_SetPowerModeInternalTest.cpp",
"SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
"SchedulerTest.cpp",
- "SetFrameRateTest.cpp",
"RefreshRateSelectorTest.cpp",
"RefreshRateStatsTest.cpp",
"RegionSamplingTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
deleted file mode 100644
index d30d5b8..0000000
--- a/services/surfaceflinger/tests/unittests/FrameRateSelectionPriorityTest.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * 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>
-
-#include "Layer.h"
-#include "TestableSurfaceFlinger.h"
-#include "mock/DisplayHardware/MockComposer.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;
-
-/**
- * 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;
-
- sp<Layer> createBufferStateLayer();
- sp<Layer> createEffectLayer();
-
- void setParent(Layer* child, Layer* parent);
- void commitTransaction(Layer* layer);
-
- TestableSurfaceFlinger mFlinger;
-
- 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());
-
- mFlinger.setupMockScheduler();
- mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
-}
-
-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<Layer> RefreshRateSelectionTest::createBufferStateLayer() {
- sp<Client> client;
- LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", LAYER_FLAGS,
- LayerMetadata());
- return sp<Layer>::make(args);
-}
-
-sp<Layer> RefreshRateSelectionTest::createEffectLayer() {
- sp<Client> client;
- LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", LAYER_FLAGS, LayerMetadata());
- return sp<Layer>::make(args);
-}
-
-void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
- child->setParent(sp<Layer>::fromExisting(parent));
-}
-
-void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
- layer->commitTransaction();
-}
-
-namespace {
-
-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
diff --git a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp b/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
deleted file mode 100644
index 866eb08..0000000
--- a/services/surfaceflinger/tests/unittests/FrameRateSelectionStrategyTest.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_TAG
-#define LOG_TAG "LibSurfaceFlingerUnittests"
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <gui/LayerMetadata.h>
-
-#include "Layer.h"
-#include "LayerTestUtils.h"
-#include "TestableSurfaceFlinger.h"
-#include "mock/DisplayHardware/MockComposer.h"
-
-namespace android {
-
-using testing::_;
-using testing::DoAll;
-using testing::Mock;
-using testing::SetArgPointee;
-
-using android::Hwc2::IComposer;
-using android::Hwc2::IComposerClient;
-
-using scheduler::LayerHistory;
-
-using FrameRate = Layer::FrameRate;
-using FrameRateCompatibility = Layer::FrameRateCompatibility;
-using FrameRateSelectionStrategy = scheduler::LayerInfo::FrameRateSelectionStrategy;
-
-/**
- * This class tests the behaviour of Layer::setFrameRateSelectionStrategy.
- */
-class FrameRateSelectionStrategyTest : public BaseLayerTest {
-protected:
- const FrameRate FRAME_RATE_VOTE1 = FrameRate(11_Hz, FrameRateCompatibility::Default);
- const FrameRate FRAME_RATE_VOTE2 = FrameRate(22_Hz, FrameRateCompatibility::Default);
- const FrameRate FRAME_RATE_VOTE3 = FrameRate(33_Hz, FrameRateCompatibility::Default);
- const FrameRate FRAME_RATE_DEFAULT = FrameRate(Fps(), FrameRateCompatibility::Default);
- const FrameRate FRAME_RATE_TREE = FrameRate(Fps(), FrameRateCompatibility::NoVote);
-
- FrameRateSelectionStrategyTest();
-
- void addChild(sp<Layer> layer, sp<Layer> child);
- void removeChild(sp<Layer> layer, sp<Layer> child);
- void commitTransaction();
-
- std::vector<sp<Layer>> mLayers;
-};
-
-FrameRateSelectionStrategyTest::FrameRateSelectionStrategyTest() {
- 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.setupComposer(std::make_unique<Hwc2::mock::Composer>());
-}
-
-void FrameRateSelectionStrategyTest::addChild(sp<Layer> layer, sp<Layer> child) {
- layer->addChild(child);
-}
-
-void FrameRateSelectionStrategyTest::removeChild(sp<Layer> layer, sp<Layer> child) {
- layer->removeChild(child);
-}
-
-void FrameRateSelectionStrategyTest::commitTransaction() {
- for (auto layer : mLayers) {
- layer->commitTransaction();
- }
-}
-
-namespace {
-
-INSTANTIATE_TEST_SUITE_P(PerLayerType, FrameRateSelectionStrategyTest,
- testing::Values(std::make_shared<BufferStateLayerFactory>(),
- std::make_shared<EffectLayerFactory>()),
- PrintToStringParamName);
-
-TEST_P(FrameRateSelectionStrategyTest, SetAndGet) {
- EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1);
-
- const auto& layerFactory = GetParam();
- auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- layer->setFrameRate(FRAME_RATE_VOTE1.vote);
- layer->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
- layer->getDrawingState().frameRateSelectionStrategy);
-}
-
-TEST_P(FrameRateSelectionStrategyTest, SetChildOverrideChildren) {
- EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).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.vote);
- child2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- parent->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- child1->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
- child2->getDrawingState().frameRateSelectionStrategy);
-}
-
-TEST_P(FrameRateSelectionStrategyTest, SetParentOverrideChildren) {
- EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1);
-
- const auto& layerFactory = GetParam();
- auto layer1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- auto layer2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- auto layer3 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- addChild(layer1, layer2);
- addChild(layer2, layer3);
-
- layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
- layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
- layer2->setFrameRate(FRAME_RATE_VOTE2.vote);
- layer2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
- layer3->setFrameRate(FRAME_RATE_VOTE3.vote);
- commitTransaction();
-
- EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
- layer1->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE1, layer2->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
- layer2->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE1, layer3->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- layer3->getDrawingState().frameRateSelectionStrategy);
-
- layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::Propagate);
- commitTransaction();
-
- EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- layer1->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
- layer2->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE2, layer3->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- layer3->getDrawingState().frameRateSelectionStrategy);
-}
-
-TEST_P(FrameRateSelectionStrategyTest, OverrideChildrenAndSelf) {
- EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1);
-
- const auto& layerFactory = GetParam();
- auto layer1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- auto layer2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- auto layer3 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- addChild(layer1, layer2);
- addChild(layer2, layer3);
-
- layer1->setFrameRate(FRAME_RATE_VOTE1.vote);
- layer2->setFrameRate(FRAME_RATE_VOTE2.vote);
- layer2->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::Self);
- commitTransaction();
-
- EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- layer1->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Self,
- layer2->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_DEFAULT, layer3->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- layer3->getDrawingState().frameRateSelectionStrategy);
-
- layer1->setFrameRateSelectionStrategy(FrameRateSelectionStrategy::OverrideChildren);
- commitTransaction();
-
- EXPECT_EQ(FRAME_RATE_VOTE1, layer1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
- layer1->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE1, layer2->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Self,
- layer2->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE1, layer3->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- layer3->getDrawingState().frameRateSelectionStrategy);
-
- layer1->setFrameRate(FRAME_RATE_DEFAULT.vote);
- commitTransaction();
-
- EXPECT_EQ(FRAME_RATE_TREE, layer1->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::OverrideChildren,
- layer1->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE2, layer2->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Self,
- layer2->getDrawingState().frameRateSelectionStrategy);
- EXPECT_EQ(FRAME_RATE_VOTE2, layer3->getFrameRateForLayerTree());
- EXPECT_EQ(FrameRateSelectionStrategy::Propagate,
- layer3->getDrawingState().frameRateSelectionStrategy);
-}
-
-} // namespace
-} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
index a61fa1e..52bb07a 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -38,6 +38,7 @@
namespace android::scheduler {
using android::mock::createDisplayMode;
+using android::mock::createVrrDisplayMode;
using namespace com::android::graphics::surfaceflinger;
class LayerHistoryIntegrationTest : public surfaceflinger::frontend::LayerSnapshotTestBase {
@@ -53,6 +54,8 @@
static constexpr Fps HI_FPS = 90_Hz;
static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs();
+ static constexpr auto kVrrModeId = DisplayModeId(2);
+
LayerHistoryIntegrationTest() : LayerSnapshotTestBase() {
mFlinger.resetScheduler(mScheduler);
mLifecycleManager = {};
@@ -71,6 +74,13 @@
updateLayerSnapshotsAndLayerHistory(time);
}
+ void setFrontBufferWithPresentTime(sp<Layer>& layer, nsecs_t time) {
+ uint32_t sequence = static_cast<uint32_t>(layer->sequence);
+ setFrontBuffer(sequence);
+ layer->setDesiredPresentTime(time, false /*autotimestamp*/);
+ updateLayerSnapshotsAndLayerHistory(time);
+ }
+
LayerHistory& history() { return mScheduler->mutableLayerHistory(); }
const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); }
@@ -135,6 +145,21 @@
return layer;
}
+ auto createLegacyAndFrontedEndLayerWithUid(uint32_t sequence, gui::Uid uid) {
+ std::string layerName = "test layer:" + std::to_string(sequence);
+ auto args = LayerCreationArgs{mFlinger.flinger(),
+ nullptr,
+ layerName,
+ 0,
+ {},
+ std::make_optional<uint32_t>(sequence)};
+ args.ownerUid = uid.val();
+ const auto layer = sp<Layer>::make(args);
+ mFlinger.injectLegacyLayer(layer);
+ createRootLayerWithUid(sequence, uid);
+ return layer;
+ }
+
auto destroyLayer(sp<Layer>& layer) {
uint32_t sequence = static_cast<uint32_t>(layer->sequence);
mFlinger.releaseLegacyLayer(sequence);
@@ -157,12 +182,13 @@
ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate);
}
- std::shared_ptr<RefreshRateSelector> mSelector =
- std::make_shared<RefreshRateSelector>(makeModes(createDisplayMode(DisplayModeId(0),
- LO_FPS),
- createDisplayMode(DisplayModeId(1),
- HI_FPS)),
- DisplayModeId(0));
+ std::shared_ptr<RefreshRateSelector> mSelector = std::make_shared<RefreshRateSelector>(
+ makeModes(createDisplayMode(DisplayModeId(0), LO_FPS),
+ createDisplayMode(DisplayModeId(1), HI_FPS),
+ createVrrDisplayMode(kVrrModeId, HI_FPS,
+ hal::VrrConfig{.minFrameIntervalNs =
+ HI_FPS.getPeriodNsecs()})),
+ DisplayModeId(0));
mock::SchedulerCallback mSchedulerCallback;
TestableSurfaceFlinger mFlinger;
@@ -214,6 +240,146 @@
EXPECT_EQ(1u, activeLayerCount());
}
+TEST_F(LayerHistoryIntegrationTest, oneLayer) {
+ createLegacyAndFrontedEndLayer(1);
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ // No layers returned if no layers are active.
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ // Max returned if active layers have insufficient history.
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ setBuffer(1);
+ updateLayerSnapshotsAndLayerHistory(time);
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ time += LO_FPS_PERIOD;
+ }
+
+ // Max is returned since we have enough history but there is no timestamp votes.
+ for (size_t i = 0; i < 10; i++) {
+ setBuffer(1);
+ updateLayerSnapshotsAndLayerHistory(time);
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ time += LO_FPS_PERIOD;
+ }
+}
+
+TEST_F(LayerHistoryIntegrationTest, gameFrameRateOverrideMapping) {
+ SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
+
+ history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 60.0f}));
+
+ auto overridePair = history().getGameFrameRateOverride(0);
+ EXPECT_EQ(0_Hz, overridePair.first);
+ EXPECT_EQ(60_Hz, overridePair.second);
+
+ history().updateGameModeFrameRateOverride(FrameRateOverride({0, 40.0f}));
+ history().updateGameModeFrameRateOverride(FrameRateOverride({1, 120.0f}));
+
+ overridePair = history().getGameFrameRateOverride(0);
+ EXPECT_EQ(40_Hz, overridePair.first);
+ EXPECT_EQ(60_Hz, overridePair.second);
+
+ overridePair = history().getGameFrameRateOverride(1);
+ EXPECT_EQ(120_Hz, overridePair.first);
+ EXPECT_EQ(0_Hz, overridePair.second);
+
+ history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 0.0f}));
+ history().updateGameModeFrameRateOverride(FrameRateOverride({1, 0.0f}));
+
+ overridePair = history().getGameFrameRateOverride(0);
+ EXPECT_EQ(40_Hz, overridePair.first);
+ EXPECT_EQ(0_Hz, overridePair.second);
+
+ overridePair = history().getGameFrameRateOverride(1);
+ EXPECT_EQ(0_Hz, overridePair.first);
+ EXPECT_EQ(0_Hz, overridePair.second);
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerGameFrameRateOverride) {
+ SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
+
+ const uid_t uid = 0;
+ const Fps gameDefaultFrameRate = Fps::fromValue(30.0f);
+ const Fps gameModeFrameRate = Fps::fromValue(60.0f);
+
+ auto layer = createLegacyAndFrontedEndLayerWithUid(1, gui::Uid(uid));
+ showLayer(1);
+
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ // update game default frame rate override
+ history().updateGameDefaultFrameRateOverride(
+ FrameRateOverride({uid, gameDefaultFrameRate.getValue()}));
+
+ LayerHistory::Summary summary;
+ scheduler::LayerProps layerProps = {
+ .visible = true,
+ .bounds = {0, 0, 100, 100},
+ .transform = {},
+ .setFrameRateVote = {},
+ .frameRateSelectionPriority = Layer::PRIORITY_UNSET,
+ .isSmallDirty = false,
+ .isFrontBuffered = false,
+ };
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += gameDefaultFrameRate.getPeriodNsecs();
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+ ASSERT_EQ(30.0_Hz, summary[0].desiredRefreshRate);
+
+ // test against setFrameRate vote
+ setFrameRate(1,
+ Layer::FrameRate(Fps::fromValue(120.0f), Layer::FrameRateCompatibility::Default));
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ const Fps setFrameRate = Fps::fromValue(120.0f);
+ layerProps.setFrameRateVote =
+ Layer::FrameRate(setFrameRate, Layer::FrameRateCompatibility::Default);
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += setFrameRate.getPeriodNsecs();
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+ ASSERT_EQ(120.0_Hz, summary[0].desiredRefreshRate);
+
+ // update game mode frame rate override
+ history().updateGameModeFrameRateOverride(
+ FrameRateOverride({uid, gameModeFrameRate.getValue()}));
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += gameModeFrameRate.getPeriodNsecs();
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+ ASSERT_EQ(60.0_Hz, summary[0].desiredRefreshRate);
+}
+
TEST_F(LayerHistoryIntegrationTest, oneInvisibleLayer) {
createLegacyAndFrontedEndLayer(1);
nsecs_t time = systemTime();
@@ -238,6 +404,110 @@
EXPECT_EQ(0u, activeLayerCount());
}
+TEST_F(LayerHistoryIntegrationTest, explicitTimestamp) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(LO_FPS, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerNoVote) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerMinVote) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Min);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerMaxVote) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Max);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += LO_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVote) {
createLegacyAndFrontedEndLayer(1);
setFrameRate(1, 73.4f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
@@ -273,6 +543,335 @@
EXPECT_EQ(1, frequentLayerCount(time));
}
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitExactVote2) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ setFrameRate(1, 73.4f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became infrequent, but the vote stays
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitGte_vrr) {
+ // Set the test to be on a vrr mode.
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+ mSelector->setActiveMode(kVrrModeId, HI_FPS);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (33_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_GTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRateCategory(1, 0);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
+
+ // layer became inactive, but the vote stays
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
+}
+
+// Test for MRR device with VRR features enabled.
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitGte_nonVrr) {
+ SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
+ // The vrr_config flag is explicitly not set false because this test for an MRR device
+ // should still work in a VRR-capable world.
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (33_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_GTE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRateCategory(1, 0);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
+
+ // layer became infrequent, but the vote stays
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) {
+ SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (73.4_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH);
+
+ // Set default to Min so it is obvious that the vote reset triggered.
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Min);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ // There is only 1 LayerRequirement due to the disabled flag frame_rate_category_mrr.
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
+}
+
+// This test case should be the same as oneLayerNoVote except instead of layer vote is NoVote,
+// the category is NoPreference.
+TEST_F(LayerHistoryIntegrationTest, oneLayerCategoryNoPreference) {
+ SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (0_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_NO_PREFERENCE);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ EXPECT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became infrequent
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ EXPECT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithCategory) {
+ SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (73.4_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ // There are 2 LayerRequirement's due to the frame rate category.
+ ASSERT_EQ(2u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ // First LayerRequirement is the layer's category specification
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
+
+ // Second LayerRequirement is the frame rate specification
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[1].vote);
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[1].frameRateCategory);
+
+ // layer became infrequent, but the vote stays
+ setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(2u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVoteWithCategoryNotVisibleDoesNotVote) {
+ SET_FLAG_FOR_TEST(flags::misc1, true);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ hideLayer(1);
+ setFrameRate(1, (12.34_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ // Layer is not visible, so the layer is moved to inactive, infrequent, and it will not have
+ // votes to consider for refresh rate selection.
+ ASSERT_EQ(0u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayer) {
+ SET_FLAG_FOR_TEST(flags::misc1, false);
+
+ auto explicitVisiblelayer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (60_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, 0);
+
+ auto explicitInvisiblelayer = createLegacyAndFrontedEndLayer(2);
+ hideLayer(2);
+ setFrameRate(2, (90_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, 0);
+
+ nsecs_t time = systemTime();
+
+ // Post a buffer to the layers to make them active
+ setBuffer(1);
+ setBuffer(2);
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ EXPECT_EQ(2u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(2u, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayerDoesNotVote) {
+ SET_FLAG_FOR_TEST(flags::misc1, true);
+
+ auto explicitVisiblelayer = createLegacyAndFrontedEndLayer(1);
+ showLayer(1);
+ setFrameRate(1, (60_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, 0);
+
+ auto explicitInvisiblelayer = createLegacyAndFrontedEndLayer(2);
+ hideLayer(2);
+ setFrameRate(2, (90_Hz).getValue(), ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, 0);
+
+ nsecs_t time = systemTime();
+
+ // Post a buffer to the layers to make them active
+ setBuffer(1);
+ setBuffer(2);
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ EXPECT_EQ(2u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, frontBufferedLayerVotesMax) {
+ SET_FLAG_FOR_TEST(flags::vrr_config, true);
+
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ setFrontBuffer(1);
+ showLayer(1);
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // layer is active but infrequent.
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setFrontBufferWithPresentTime(layer, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // Layer still active due to front buffering, but it's infrequent.
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+}
+
TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitCategory) {
SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
@@ -805,7 +1404,15 @@
// layer is active but infrequent.
for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
- auto props = layer->getLayerProps();
+ scheduler::LayerProps props = {
+ .visible = false,
+ .bounds = {0, 0, 100, 100},
+ .transform = {},
+ .setFrameRateVote = {},
+ .frameRateSelectionPriority = Layer::PRIORITY_UNSET,
+ .isSmallDirty = false,
+ .isFrontBuffered = false,
+ };
if (i % 3 == 0) {
props.isSmallDirty = false;
} else {
@@ -838,8 +1445,15 @@
// uiLayer is updating small dirty.
for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) {
- auto props = uiLayer->getLayerProps();
- props.isSmallDirty = true;
+ scheduler::LayerProps props = {
+ .visible = false,
+ .bounds = {0, 0, 100, 100},
+ .transform = {},
+ .setFrameRateVote = {},
+ .frameRateSelectionPriority = Layer::PRIORITY_UNSET,
+ .isSmallDirty = true,
+ .isFrontBuffered = false,
+ };
setBuffer(1);
uiLayer->setDesiredPresentTime(0, false /*autotimestamp*/);
updateLayerSnapshotsAndLayerHistory(time);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
deleted file mode 100644
index 088d0d2..0000000
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ /dev/null
@@ -1,1573 +0,0 @@
-/*
- * 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 "-Wextra"
-
-#undef LOG_TAG
-#define LOG_TAG "LayerHistoryTest"
-
-#include <Layer.h>
-#include <com_android_graphics_surfaceflinger_flags.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <log/log.h>
-
-#include <common/test/FlagUtils.h>
-#include "FpsOps.h"
-#include "Scheduler/LayerHistory.h"
-#include "Scheduler/LayerInfo.h"
-#include "TestableScheduler.h"
-#include "TestableSurfaceFlinger.h"
-#include "mock/DisplayHardware/MockDisplayMode.h"
-#include "mock/MockLayer.h"
-#include "mock/MockSchedulerCallback.h"
-
-using testing::_;
-using testing::Return;
-using testing::ReturnRef;
-
-namespace android::scheduler {
-
-using MockLayer = android::mock::MockLayer;
-
-using android::mock::createDisplayMode;
-using android::mock::createVrrDisplayMode;
-
-// WARNING: LEGACY TESTS FOR LEGACY FRONT END
-// Update LayerHistoryIntegrationTest instead
-class LayerHistoryTest : public testing::Test {
-protected:
- static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE;
- static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::kMaxPeriodForFrequentLayerNs;
- static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfo::kFrequentLayerWindowSize;
- static constexpr auto PRESENT_TIME_HISTORY_DURATION = LayerInfo::HISTORY_DURATION;
-
- static constexpr Fps LO_FPS = 30_Hz;
- static constexpr auto LO_FPS_PERIOD = LO_FPS.getPeriodNsecs();
-
- static constexpr Fps HI_FPS = 90_Hz;
- static constexpr auto HI_FPS_PERIOD = HI_FPS.getPeriodNsecs();
-
- LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
-
- LayerHistory& history() { return mScheduler->mutableLayerHistory(); }
- const LayerHistory& history() const { return mScheduler->mutableLayerHistory(); }
-
- LayerHistory::Summary summarizeLayerHistory(nsecs_t now) {
- // LayerHistory::summarize makes no guarantee of the order of the elements in the summary
- // however, for testing only, a stable order is required, therefore we sort the list here.
- // Any tests requiring ordered results must create layers with names.
- auto summary = history().summarize(*mScheduler->refreshRateSelector(), now);
- std::sort(summary.begin(), summary.end(),
- [](const RefreshRateSelector::LayerRequirement& lhs,
- const RefreshRateSelector::LayerRequirement& rhs) -> bool {
- return lhs.name < rhs.name;
- });
- return summary;
- }
-
- size_t layerCount() const { return mScheduler->layerHistorySize(); }
- size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS {
- return history().mActiveLayerInfos.size();
- }
-
- auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
- const auto& infos = history().mActiveLayerInfos;
- return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) {
- return pair.second.second->isFrequent(now).isFrequent;
- });
- }
-
- auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
- const auto& infos = history().mActiveLayerInfos;
- return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) {
- return pair.second.second->isAnimating(now);
- });
- }
-
- auto clearLayerHistoryCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
- const auto& infos = history().mActiveLayerInfos;
- return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) {
- return pair.second.second->isFrequent(now).clearHistory;
- });
- }
-
- void setDefaultLayerVote(Layer* layer,
- LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
- auto [found, layerPair] = history().findLayer(layer->getSequence());
- if (found != LayerHistory::LayerStatus::NotFound) {
- layerPair->second->setDefaultLayerVote(vote);
- }
- }
-
- auto createLayer() { return sp<MockLayer>::make(mFlinger.flinger()); }
- auto createLayer(std::string name) {
- return sp<MockLayer>::make(mFlinger.flinger(), std::move(name));
- }
- auto createLayer(std::string name, uint32_t uid) {
- return sp<MockLayer>::make(mFlinger.flinger(), std::move(name), std::move(uid));
- }
-
- void recordFramesAndExpect(const sp<MockLayer>& layer, nsecs_t& time, Fps frameRate,
- Fps desiredRefreshRate, int numFrames) {
- LayerHistory::Summary summary;
- for (int i = 0; i < numFrames; i++) {
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += frameRate.getPeriodNsecs();
-
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate);
- }
-
- static constexpr auto kVrrModeId = DisplayModeId(2);
- std::shared_ptr<RefreshRateSelector> mSelector = std::make_shared<RefreshRateSelector>(
- makeModes(createDisplayMode(DisplayModeId(0), LO_FPS),
- createDisplayMode(DisplayModeId(1), HI_FPS),
- createVrrDisplayMode(kVrrModeId, HI_FPS,
- hal::VrrConfig{.minFrameIntervalNs =
- HI_FPS.getPeriodNsecs()})),
- DisplayModeId(0));
-
- mock::SchedulerCallback mSchedulerCallback;
- TestableSurfaceFlinger mFlinger;
- TestableScheduler* mScheduler = new TestableScheduler(mSelector, mFlinger, mSchedulerCallback);
-};
-
-namespace {
-
-using namespace com::android::graphics::surfaceflinger;
-
-TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) {
- const auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
- EXPECT_CALL(*layer, getDefaultFrameRateCompatibility())
- .WillOnce(Return(FrameRateCompatibility::NoVote));
-
- EXPECT_EQ(1, layerCount());
- EXPECT_EQ(0, activeLayerCount());
-
- nsecs_t time = systemTime();
-
- // No layers returned if no layers are active.
- EXPECT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(0, activeLayerCount());
-
- history().record(layer->getSequence(), layer->getLayerProps(), 0, time,
- LayerHistory::LayerUpdateType::Buffer);
- history().setDefaultFrameRateCompatibility(layer->getSequence(),
-
- layer->getDefaultFrameRateCompatibility(),
- true /* contentDetectionEnabled */);
-
- EXPECT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(1, activeLayerCount());
-}
-
-TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) {
- const auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
- EXPECT_CALL(*layer, getDefaultFrameRateCompatibility())
- .WillOnce(Return(FrameRateCompatibility::Min));
-
- EXPECT_EQ(1, layerCount());
- EXPECT_EQ(0, activeLayerCount());
-
- nsecs_t time = systemTime();
-
- EXPECT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(0, activeLayerCount());
-
- history().record(layer->getSequence(), layer->getLayerProps(), 0, time,
- LayerHistory::LayerUpdateType::Buffer);
- history().setDefaultFrameRateCompatibility(layer->getSequence(),
- layer->getDefaultFrameRateCompatibility(),
- true /* contentDetectionEnabled */);
-
- auto summary = summarizeLayerHistory(time);
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
-
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
-}
-
-TEST_F(LayerHistoryTest, oneLayer) {
- const auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
-
- // history().registerLayer(layer, LayerHistory::LayerVoteType::Max);
-
- EXPECT_EQ(1, layerCount());
- EXPECT_EQ(0, activeLayerCount());
-
- nsecs_t time = systemTime();
-
- // No layers returned if no layers are active.
- EXPECT_TRUE(summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), 0, time,
- LayerHistory::LayerUpdateType::Buffer);
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- time += LO_FPS_PERIOD;
- }
-
- // Max is returned since we have enough history but there is no timestamp votes.
- for (int i = 0; i < 10; i++) {
- history().record(layer->getSequence(), layer->getLayerProps(), 0, time,
- LayerHistory::LayerUpdateType::Buffer);
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- time += LO_FPS_PERIOD;
- }
-}
-
-TEST_F(LayerHistoryTest, gameFrameRateOverrideMapping) {
- SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
-
- history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 60.0f}));
-
- auto overridePair = history().getGameFrameRateOverride(0);
- EXPECT_EQ(0_Hz, overridePair.first);
- EXPECT_EQ(60_Hz, overridePair.second);
-
- history().updateGameModeFrameRateOverride(FrameRateOverride({0, 40.0f}));
- history().updateGameModeFrameRateOverride(FrameRateOverride({1, 120.0f}));
-
- overridePair = history().getGameFrameRateOverride(0);
- EXPECT_EQ(40_Hz, overridePair.first);
- EXPECT_EQ(60_Hz, overridePair.second);
-
- overridePair = history().getGameFrameRateOverride(1);
- EXPECT_EQ(120_Hz, overridePair.first);
- EXPECT_EQ(0_Hz, overridePair.second);
-
- history().updateGameDefaultFrameRateOverride(FrameRateOverride({0, 0.0f}));
- history().updateGameModeFrameRateOverride(FrameRateOverride({1, 0.0f}));
-
- overridePair = history().getGameFrameRateOverride(0);
- EXPECT_EQ(40_Hz, overridePair.first);
- EXPECT_EQ(0_Hz, overridePair.second);
-
- overridePair = history().getGameFrameRateOverride(1);
- EXPECT_EQ(0_Hz, overridePair.first);
- EXPECT_EQ(0_Hz, overridePair.second);
-}
-
-TEST_F(LayerHistoryTest, oneLayerGameFrameRateOverride) {
- SET_FLAG_FOR_TEST(flags::game_default_frame_rate, true);
-
- const uid_t uid = 0;
- const Fps gameDefaultFrameRate = Fps::fromValue(30.0f);
- const Fps gameModeFrameRate = Fps::fromValue(60.0f);
- const auto layer = createLayer("GameFrameRateLayer", uid);
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
- EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid));
-
- EXPECT_EQ(1, layerCount());
- EXPECT_EQ(0, activeLayerCount());
-
- // update game default frame rate override
- history().updateGameDefaultFrameRateOverride(
- FrameRateOverride({uid, gameDefaultFrameRate.getValue()}));
-
- nsecs_t time = systemTime();
- LayerHistory::Summary summary;
- for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += gameDefaultFrameRate.getPeriodNsecs();
-
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
- ASSERT_EQ(30.0_Hz, summary[0].desiredRefreshRate);
-
- // test against setFrameRate vote
- const Fps setFrameRate = Fps::fromValue(120.0f);
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(
- Return(Layer::FrameRate(setFrameRate, Layer::FrameRateCompatibility::Default)));
-
- for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += setFrameRate.getPeriodNsecs();
-
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
- ASSERT_EQ(120.0_Hz, summary[0].desiredRefreshRate);
-
- // update game mode frame rate override
- history().updateGameModeFrameRateOverride(
- FrameRateOverride({uid, gameModeFrameRate.getValue()}));
-
- for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += gameModeFrameRate.getPeriodNsecs();
-
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
- ASSERT_EQ(60.0_Hz, summary[0].desiredRefreshRate);
-}
-
-TEST_F(LayerHistoryTest, 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->getSequence(), layer->getLayerProps(), 0, time,
- LayerHistory::LayerUpdateType::Buffer);
- auto summary = summarizeLayerHistory(time);
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- // Layer is still considered inactive so we expect to get Min
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
-
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
- history().record(layer->getSequence(), layer->getLayerProps(), 0, time,
- LayerHistory::LayerUpdateType::Buffer);
-
- summary = summarizeLayerHistory(time);
- EXPECT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(0, activeLayerCount());
-}
-
-TEST_F(LayerHistoryTest, 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += LO_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(LO_FPS, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, oneLayerNoVote) {
- const auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
-
- setDefaultLayerVote(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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- ASSERT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer became inactive
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(0, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, oneLayerMinVote) {
- const auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
-
- setDefaultLayerVote(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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer became inactive
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(0, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, oneLayerMaxVote) {
- const auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
-
- setDefaultLayerVote(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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += LO_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer became inactive
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_TRUE(summarizeLayerHistory(time).empty());
- EXPECT_EQ(0, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, oneLayerExplicitVote) {
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(
- Return(Layer::FrameRate(73.4_Hz, 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer became infrequent, but the vote stays
- setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) {
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(
- Layer::FrameRate(73.4_Hz, 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer became infrequent, but the vote stays
- setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, oneLayerExplicitGte_vrr) {
- // Set the test to be on a vrr mode.
- SET_FLAG_FOR_TEST(flags::vrr_config, true);
- mSelector->setActiveMode(kVrrModeId, HI_FPS);
-
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte,
- Seamlessness::OnlySeamless,
- FrameRateCategory::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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
-
- // layer became inactive, but the vote stays
- setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
-}
-
-// Test for MRR device with VRR features enabled.
-TEST_F(LayerHistoryTest, oneLayerExplicitGte_nonVrr) {
- SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
- // The vrr_config flag is explicitly not set false because this test for an MRR device
- // should still work in a VRR-capable world.
-
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte,
- Seamlessness::OnlySeamless,
- FrameRateCategory::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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
-
- // layer became infrequent, but the vote stays
- setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
-}
-
-TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) {
- SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false);
-
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(
- Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default,
- Seamlessness::OnlySeamless, FrameRateCategory::High)));
-
- // Set default to Min so it is obvious that the vote reset triggered.
- setDefaultLayerVote(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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- // There is only 1 LayerRequirement due to the disabled flag frame_rate_category_mrr.
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory);
-}
-
-TEST_F(LayerHistoryTest, oneLayerExplicitCategory) {
- SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
-
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(
- Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default,
- Seamlessness::OnlySeamless, FrameRateCategory::High)));
-
- 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- // First LayerRequirement is the frame rate specification
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
-
- // layer became infrequent, but the vote stays
- setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
-}
-
-// This test case should be the same as oneLayerNoVote except instead of layer vote is NoVote,
-// the category is NoPreference.
-TEST_F(LayerHistoryTest, oneLayerCategoryNoPreference) {
- SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
-
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(Layer::FrameRate(0_Hz, Layer::FrameRateCompatibility::Default,
- Seamlessness::OnlySeamless,
- FrameRateCategory::NoPreference)));
-
- 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- EXPECT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer became infrequent
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- EXPECT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory) {
- SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true);
-
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(
- Return(Layer::FrameRate(73.4_Hz, Layer::FrameRateCompatibility::Default,
- Seamlessness::OnlySeamless, FrameRateCategory::High)));
-
- 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- // There are 2 LayerRequirement's due to the frame rate category.
- ASSERT_EQ(2, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- // First LayerRequirement is the layer's category specification
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
-
- // Second LayerRequirement is the frame rate specification
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[1].vote);
- EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[1].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[1].frameRateCategory);
-
- // layer became infrequent, but the vote stays
- setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(2, summarizeLayerHistory(time).size());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitCategory, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(FrameRateCategory::High, summarizeLayerHistory(time)[0].frameRateCategory);
-}
-
-TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategoryNotVisibleDoesNotVote) {
- SET_FLAG_FOR_TEST(flags::misc1, true);
-
- auto layer = createLayer();
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
- EXPECT_CALL(*layer, getFrameRateForLayerTree())
- .WillRepeatedly(
- Return(Layer::FrameRate(12.34_Hz, Layer::FrameRateCompatibility::Default,
- Seamlessness::OnlySeamless, FrameRateCategory::High)));
-
- 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- }
-
- // Layer is not visible, so the layer is moved to inactive, infrequent, and it will not have
- // votes to consider for refresh rate selection.
- ASSERT_EQ(0, summarizeLayerHistory(time).size());
- EXPECT_EQ(0, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, multipleLayers) {
- auto layer1 = createLayer("A");
- auto layer2 = createLayer("B");
- auto layer3 = createLayer("C");
-
- 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));
-
- LayerHistory::Summary summary;
-
- // layer1 is active but infrequent.
- for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
- history().record(layer1->getSequence(), layer1->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- summary = summarizeLayerHistory(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->getSequence(), layer2->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- summary = summarizeLayerHistory(time);
- }
-
- // layer1 is still active but infrequent.
- history().record(layer1->getSequence(), layer1->getLayerProps(), 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_EQ(HI_FPS, summarizeLayerHistory(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->getSequence(), layer2->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += LO_FPS_PERIOD;
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_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->getSequence(), layer2->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- }
-
- history().record(layer3->getSequence(), layer3->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(2, summary.size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_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->getSequence(), layer3->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- summary = summarizeLayerHistory(time);
- ASSERT_EQ(2, summary.size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_EQ(HI_FPS, summary[1].desiredRefreshRate);
- EXPECT_EQ(2, activeLayerCount());
- EXPECT_EQ(2, frequentLayerCount(time));
-
- // layer1 expires.
- layer1.clear();
- summary = summarizeLayerHistory(time);
- ASSERT_EQ(2, summary.size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
- EXPECT_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->getSequence(), layer2->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += LO_FPS_PERIOD;
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer2 expires.
- layer2.clear();
- summary = summarizeLayerHistory(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->getSequence(), layer3->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_EQ(HI_FPS, summary[0].desiredRefreshRate);
- EXPECT_EQ(1, layerCount());
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-
- // layer3 expires.
- layer3.clear();
- summary = summarizeLayerHistory(time);
- EXPECT_TRUE(summary.empty());
- EXPECT_EQ(0, layerCount());
- EXPECT_EQ(0, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
-
- EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
-
- EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(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 even 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
-
- EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- }
-
- // More quick frames will get us to frequent again
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
-
- EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, invisibleExplicitLayer) {
- SET_FLAG_FOR_TEST(flags::misc1, false);
-
- auto explicitVisiblelayer = createLayer();
- auto explicitInvisiblelayer = createLayer();
-
- EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(
- Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
-
- EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false));
- EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(
- Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
-
- nsecs_t time = systemTime();
-
- // Post a buffer to the layers to make them active
- history().record(explicitVisiblelayer->getSequence(), explicitVisiblelayer->getLayerProps(),
- time, time, LayerHistory::LayerUpdateType::Buffer);
- history().record(explicitInvisiblelayer->getSequence(), explicitInvisiblelayer->getLayerProps(),
- time, time, LayerHistory::LayerUpdateType::Buffer);
-
- EXPECT_EQ(2, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(2, activeLayerCount());
- EXPECT_EQ(2, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, invisibleExplicitLayerDoesNotVote) {
- SET_FLAG_FOR_TEST(flags::misc1, true);
-
- auto explicitVisiblelayer = createLayer();
- auto explicitInvisiblelayer = createLayer();
-
- EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(
- Layer::FrameRate(60_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
-
- EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false));
- EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree())
- .WillRepeatedly(Return(
- Layer::FrameRate(90_Hz, Layer::FrameRateCompatibility::ExactOrMultiple)));
-
- nsecs_t time = systemTime();
-
- // Post a buffer to the layers to make them active
- history().record(explicitVisiblelayer->getSequence(), explicitVisiblelayer->getLayerProps(),
- time, time, LayerHistory::LayerUpdateType::Buffer);
- history().record(explicitInvisiblelayer->getSequence(), explicitInvisiblelayer->getLayerProps(),
- time, time, LayerHistory::LayerUpdateType::Buffer);
-
- EXPECT_EQ(2, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
- summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::AnimationTX);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(1, animatingLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, frontBufferedLayerVotesMax) {
- SET_FLAG_FOR_TEST(flags::vrr_config, true);
- auto layer = createLayer();
-
- EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
- EXPECT_CALL(*layer, isFrontBuffered()).WillRepeatedly(Return(true));
-
- 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- }
-
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-
- // Layer still active due to front buffering, but it's infrequent.
- time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) {
- 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));
-
- // Fill up the window with frequent updates
- for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) {
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += (60_Hz).getPeriodNsecs();
-
- EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- }
-
- // posting a buffer after long inactivity should retain the layer as active
- time += std::chrono::nanoseconds(3s).count();
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(0, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-
- // posting more infrequent buffer should make the layer infrequent
- time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count();
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count();
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(0, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-
- // posting another buffer should keep the layer infrequent
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(0, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-
- // posting more buffers would mean starting of an animation, so making the layer frequent
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(1, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-
- // posting a buffer after long inactivity should retain the layer as active
- time += std::chrono::nanoseconds(3s).count();
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(0, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-
- // posting another buffer should keep the layer frequent
- time += (60_Hz).getPeriodNsecs();
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(0, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, inconclusiveLayerBecomingFrequent) {
- 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));
-
- // Fill up the window with frequent updates
- for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) {
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += (60_Hz).getPeriodNsecs();
-
- EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- }
-
- // posting infrequent buffers after long inactivity should make the layer
- // inconclusive but frequent.
- time += std::chrono::nanoseconds(3s).count();
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count();
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(0, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-
- // posting more buffers should make the layer frequent and switch the refresh rate to max
- // by clearing the history
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- history().record(layer->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- EXPECT_EQ(1, clearLayerHistoryCount(time));
- ASSERT_EQ(1, summarizeLayerHistory(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
- EXPECT_EQ(0, animatingLayerCount(time));
-}
-
-TEST_F(LayerHistoryTest, getFramerate) {
- 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->getSequence(), layer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
- }
-
- float expectedFramerate = 1e9f / MAX_FREQUENT_LAYER_PERIOD_NS.count();
- EXPECT_FLOAT_EQ(expectedFramerate, history().getLayerFramerate(time, layer->getSequence()));
-}
-
-TEST_F(LayerHistoryTest, 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::fromValue(fps), 60_Hz, PRESENT_TIME_HISTORY_SIZE);
- }
-}
-
-TEST_F(LayerHistoryTest, 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_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
-
- recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 30_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 30_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 60_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 60_Hz, 60_Hz, PRESENT_TIME_HISTORY_SIZE);
-}
-
-TEST_F(LayerHistoryTest, heuristicLayerNotOscillating) {
- SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, false);
-
- 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.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
-}
-
-TEST_F(LayerHistoryTest, heuristicLayerNotOscillating_useKnownRefreshRate) {
- SET_FLAG_FOR_TEST(flags::use_known_refresh_rate_for_fps_consistency, true);
-
- 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.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26.9_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 26.9_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 27.1_Hz, 24_Hz, PRESENT_TIME_HISTORY_SIZE);
- recordFramesAndExpect(layer, time, 27.1_Hz, 30_Hz, PRESENT_TIME_HISTORY_SIZE);
-}
-
-TEST_F(LayerHistoryTest, smallDirtyLayer) {
- 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));
-
- LayerHistory::Summary summary;
-
- // layer is active but infrequent.
- for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
- auto props = layer->getLayerProps();
- if (i % 3 == 0) {
- props.isSmallDirty = false;
- } else {
- props.isSmallDirty = true;
- }
-
- history().record(layer->getSequence(), props, time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
- EXPECT_GE(HI_FPS, summary[0].desiredRefreshRate);
-}
-
-TEST_F(LayerHistoryTest, smallDirtyInMultiLayer) {
- auto layer1 = createLayer("UI");
- auto layer2 = createLayer("Video");
-
- 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(30_Hz, Layer::FrameRateCompatibility::Default)));
-
- nsecs_t time = systemTime();
-
- EXPECT_EQ(2, layerCount());
- EXPECT_EQ(0, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-
- LayerHistory::Summary summary;
-
- // layer1 is updating small dirty.
- for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) {
- auto props = layer1->getLayerProps();
- props.isSmallDirty = true;
- history().record(layer1->getSequence(), props, 0 /*presentTime*/, time,
- LayerHistory::LayerUpdateType::Buffer);
- history().record(layer2->getSequence(), layer2->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
- time += HI_FPS_PERIOD;
- summary = summarizeLayerHistory(time);
- }
-
- ASSERT_EQ(1, summary.size());
- ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
- ASSERT_EQ(30_Hz, summary[0].desiredRefreshRate);
-}
-
-class LayerHistoryTestParameterized : public LayerHistoryTest,
- public testing::WithParamInterface<std::chrono::nanoseconds> {
-};
-
-TEST_P(LayerHistoryTestParameterized, 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->getSequence(), heuristicLayer->getLayerProps(), startTime,
- startTime, LayerHistory::LayerUpdateType::Buffer);
- history().record(infrequentLayer->getSequence(), heuristicLayer->getLayerProps(), 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->getSequence(), heuristicLayer->getLayerProps(), time, time,
- LayerHistory::LayerUpdateType::Buffer);
-
- if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) {
- ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates,
- totalInfrequentLayerUpdates);
- lastInfrequentUpdate = time;
- history().record(infrequentLayer->getSequence(), infrequentLayer->getLayerProps(), time,
- time, LayerHistory::LayerUpdateType::Buffer);
- infrequentLayerUpdates++;
- }
-
- if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) {
- ASSERT_NE(0, summarizeLayerHistory(time).size());
- ASSERT_GE(2, summarizeLayerHistory(time).size());
-
- bool max = false;
- bool min = false;
- Fps heuristic;
- for (const auto& layer : summarizeLayerHistory(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_EQ(24_Hz, heuristic);
- EXPECT_FALSE(max);
- if (summarizeLayerHistory(time).size() == 2) {
- EXPECT_TRUE(min);
- }
- }
- }
- }
-}
-
-INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestParameterized,
- ::testing::Values(1s, 2s, 3s, 4s, 5s));
-
-} // namespace
-} // namespace android::scheduler
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 2bb864a..2860345 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -56,6 +56,17 @@
class LayerSnapshotTest : public LayerSnapshotTestBase {
protected:
+ const Layer::FrameRate FRAME_RATE_VOTE1 =
+ Layer::FrameRate(67_Hz, scheduler::FrameRateCompatibility::Default);
+ const Layer::FrameRate FRAME_RATE_VOTE2 =
+ Layer::FrameRate(14_Hz, scheduler::FrameRateCompatibility::Default);
+ const Layer::FrameRate FRAME_RATE_VOTE3 =
+ Layer::FrameRate(99_Hz, scheduler::FrameRateCompatibility::Default);
+ const Layer::FrameRate FRAME_RATE_TREE =
+ Layer::FrameRate(Fps(), scheduler::FrameRateCompatibility::NoVote);
+ const Layer::FrameRate FRAME_RATE_NO_VOTE =
+ Layer::FrameRate(Fps(), scheduler::FrameRateCompatibility::Default);
+
LayerSnapshotTest() : LayerSnapshotTestBase() {
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
}
@@ -787,6 +798,155 @@
scheduler::FrameRateCompatibility::Default);
}
+TEST_F(LayerSnapshotTest, frameRateSetAndGet) {
+ setFrameRate(1, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ // verify parent is gets no vote
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE1);
+}
+
+TEST_F(LayerSnapshotTest, frameRateSetAndGetParent) {
+ setFrameRate(111, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_TREE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_TREE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ setFrameRate(111, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+}
+
+TEST_F(LayerSnapshotTest, frameRateSetAndGetParentAllVote) {
+ setFrameRate(1, FRAME_RATE_VOTE3.vote.rate.getValue(), 0, 0);
+ setFrameRate(11, FRAME_RATE_VOTE2.vote.rate.getValue(), 0, 0);
+ setFrameRate(111, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE3);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE2);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ setFrameRate(111, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE3);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE2);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE2);
+
+ setFrameRate(11, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE3);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE3);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE3);
+
+ setFrameRate(1, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+}
+
+TEST_F(LayerSnapshotTest, frameRateSetAndGetChild) {
+ setFrameRate(1, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ setFrameRate(1, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+}
+
+TEST_F(LayerSnapshotTest, frameRateSetAndGetChildAllVote) {
+ setFrameRate(1, FRAME_RATE_VOTE3.vote.rate.getValue(), 0, 0);
+ setFrameRate(11, FRAME_RATE_VOTE2.vote.rate.getValue(), 0, 0);
+ setFrameRate(111, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE3);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE2);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ setFrameRate(1, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_TREE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE2);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ setFrameRate(11, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_TREE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_TREE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ setFrameRate(111, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+}
+
+TEST_F(LayerSnapshotTest, frameRateSetAndGetChildAddAfterVote) {
+ setFrameRate(1, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ reparentLayer(111, 2);
+ std::vector<uint32_t> traversalOrder = {1, 11, 12, 121, 122, 1221, 13, 2, 111};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, traversalOrder);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+
+ reparentLayer(111, 11);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ setFrameRate(1, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+}
+
+TEST_F(LayerSnapshotTest, frameRateSetAndGetChildRemoveAfterVote) {
+ setFrameRate(1, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_VOTE1);
+
+ reparentLayer(111, 2);
+ std::vector<uint32_t> traversalOrder = {1, 11, 12, 121, 122, 1221, 13, 2, 111};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, traversalOrder);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+
+ setFrameRate(1, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, traversalOrder);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate, FRAME_RATE_NO_VOTE);
+}
+
+TEST_F(LayerSnapshotTest, frameRateAddChildForParentWithTreeVote) {
+ setFrameRate(11, FRAME_RATE_VOTE1.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_TREE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_VOTE1);
+ EXPECT_EQ(getSnapshot({.id = 12})->frameRate, FRAME_RATE_NO_VOTE);
+
+ setFrameRate(11, FRAME_RATE_NO_VOTE.vote.rate.getValue(), 0, 0);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate, FRAME_RATE_NO_VOTE);
+ EXPECT_EQ(getSnapshot({.id = 12})->frameRate, FRAME_RATE_NO_VOTE);
+}
+
TEST_F(LayerSnapshotTest, translateDataspace) {
setDataspace(1, ui::Dataspace::UNKNOWN);
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
@@ -965,7 +1125,7 @@
EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.vote.rate.isValid());
EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type,
scheduler::FrameRateCompatibility::NoVote);
- EXPECT_FALSE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
// verify layer 12 and all descendants (121, 122, 1221) get the requested vote
EXPECT_FALSE(getSnapshot({.id = 12})->frameRate.vote.rate.isValid());
@@ -1056,7 +1216,7 @@
EXPECT_EQ(getSnapshot({.id = 1})->frameRate.vote.type,
scheduler::FrameRateCompatibility::NoVote);
EXPECT_EQ(getSnapshot({.id = 1})->frameRate.category, FrameRateCategory::Default);
- EXPECT_FALSE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
// verify layer 12 and all descendants (121, 122, 1221) get the requested vote
EXPECT_FALSE(getSnapshot({.id = 12})->frameRate.vote.rate.isValid());
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index dddda05..358f6b0 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -168,7 +168,17 @@
// recordLayerHistory should be a noop
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
- mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, 0,
+ scheduler::LayerProps layerProps = {
+ .visible = true,
+ .bounds = {0, 0, 100, 100},
+ .transform = {},
+ .setFrameRateVote = {},
+ .frameRateSelectionPriority = Layer::PRIORITY_UNSET,
+ .isSmallDirty = false,
+ .isFrontBuffered = false,
+ };
+
+ mScheduler->recordLayerHistory(layer->getSequence(), layerProps, 0, 0,
LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
@@ -194,7 +204,16 @@
kDisplay1Mode60->getId()));
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
- mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, 0,
+ scheduler::LayerProps layerProps = {
+ .visible = true,
+ .bounds = {0, 0, 100, 100},
+ .transform = {},
+ .setFrameRateVote = {},
+ .frameRateSelectionPriority = Layer::PRIORITY_UNSET,
+ .isSmallDirty = false,
+ .isFrontBuffered = false,
+ };
+ mScheduler->recordLayerHistory(layer->getSequence(), layerProps, 0, 0,
LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(1u, mScheduler->getNumActiveLayers());
}
@@ -259,9 +278,16 @@
kDisplay1Mode60->getId()));
const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
- EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
-
- mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, systemTime(),
+ scheduler::LayerProps layerProps = {
+ .visible = true,
+ .bounds = {0, 0, 0, 0},
+ .transform = {},
+ .setFrameRateVote = {},
+ .frameRateSelectionPriority = Layer::PRIORITY_UNSET,
+ .isSmallDirty = false,
+ .isFrontBuffered = false,
+ };
+ mScheduler->recordLayerHistory(layer->getSequence(), layerProps, 0, systemTime(),
LayerHistory::LayerUpdateType::Buffer);
constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
deleted file mode 100644
index 4705dd1..0000000
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-/*
- * 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/FrameRateUtils.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 "Layer.h"
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
-#include "FpsOps.h"
-#include "LayerTestUtils.h"
-#include "TestableSurfaceFlinger.h"
-#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockVsyncController.h"
-
-namespace android {
-using testing::_;
-using testing::DoAll;
-using testing::Mock;
-using testing::SetArgPointee;
-
-using android::Hwc2::IComposer;
-using android::Hwc2::IComposerClient;
-
-using scheduler::LayerHistory;
-
-using FrameRate = Layer::FrameRate;
-using FrameRateCompatibility = Layer::FrameRateCompatibility;
-
-/**
- * This class tests the behaviour of Layer::SetFrameRate and Layer::GetFrameRate
- */
-class SetFrameRateTest : public BaseLayerTest {
-protected:
- const FrameRate FRAME_RATE_VOTE1 = FrameRate(67_Hz, FrameRateCompatibility::Default);
- const FrameRate FRAME_RATE_VOTE2 = FrameRate(14_Hz, FrameRateCompatibility::ExactOrMultiple);
- const FrameRate FRAME_RATE_VOTE3 = FrameRate(99_Hz, FrameRateCompatibility::NoVote);
- const FrameRate FRAME_RATE_TREE = FrameRate(Fps(), FrameRateCompatibility::NoVote);
- const FrameRate FRAME_RATE_NO_VOTE = FrameRate(Fps(), FrameRateCompatibility::Default);
-
- SetFrameRateTest();
-
- void addChild(sp<Layer> layer, sp<Layer> child);
- void removeChild(sp<Layer> layer, sp<Layer> child);
- void commitTransaction();
-
- 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.setupComposer(std::make_unique<Hwc2::mock::Composer>());
-}
-
-void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
- layer->addChild(child);
-}
-
-void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) {
- layer->removeChild(child);
-}
-
-void SetFrameRateTest::commitTransaction() {
- for (auto layer : mLayers) {
- layer->commitTransaction();
- }
-}
-
-namespace {
-
-TEST_P(SetFrameRateTest, SetAndGet) {
- EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1);
-
- const auto& layerFactory = GetParam();
-
- auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- layer->setFrameRate(FRAME_RATE_VOTE1.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree());
-}
-
-TEST_P(SetFrameRateTest, SetAndGetParent) {
- EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).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.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.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(*mFlinger.scheduler(), scheduleFrame(_)).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.vote);
- child1->setFrameRate(FRAME_RATE_VOTE2.vote);
- parent->setFrameRate(FRAME_RATE_VOTE3.vote);
- 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.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE2, child2->getFrameRateForLayerTree());
-
- child1->setFrameRate(FRAME_RATE_NO_VOTE.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE3, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE3, child2->getFrameRateForLayerTree());
-
- parent->setFrameRate(FRAME_RATE_NO_VOTE.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(*mFlinger.scheduler(), scheduleFrame(_)).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.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
-
- parent->setFrameRate(FRAME_RATE_NO_VOTE.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(*mFlinger.scheduler(), scheduleFrame(_)).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.vote);
- child1->setFrameRate(FRAME_RATE_VOTE2.vote);
- parent->setFrameRate(FRAME_RATE_VOTE3.vote);
- 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.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.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.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(*mFlinger.scheduler(), scheduleFrame(_)).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.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, 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_VOTE1, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
-
- parent->setFrameRate(FRAME_RATE_NO_VOTE.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(*mFlinger.scheduler(), scheduleFrame(_)).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.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
-
- removeChild(child1, child2);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
-
- parent->setFrameRate(FRAME_RATE_NO_VOTE.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(*mFlinger.scheduler(), scheduleFrame(_)).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.vote);
- 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.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());
-}
-
-INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest,
- testing::Values(std::make_shared<BufferStateLayerFactory>(),
- std::make_shared<EffectLayerFactory>()),
- PrintToStringParamName);
-
-TEST_P(SetFrameRateTest, SetOnParentActivatesTree) {
- const auto& layerFactory = GetParam();
-
- auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
-
- auto child = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- addChild(parent, child);
-
- parent->setFrameRate(FRAME_RATE_VOTE1.vote);
- commitTransaction();
-
- auto& history = mFlinger.mutableScheduler().mutableLayerHistory();
- history.record(parent->getSequence(), parent->getLayerProps(), 0, 0,
- LayerHistory::LayerUpdateType::Buffer);
- history.record(child->getSequence(), child->getLayerProps(), 0, 0,
- LayerHistory::LayerUpdateType::Buffer);
-
- const auto selectorPtr = mFlinger.mutableScheduler().refreshRateSelector();
- const auto summary = history.summarize(*selectorPtr, 0);
-
- ASSERT_EQ(2u, summary.size());
- EXPECT_EQ(FRAME_RATE_VOTE1.vote.rate, summary[0].desiredRefreshRate);
- EXPECT_EQ(FRAME_RATE_VOTE1.vote.rate, summary[1].desiredRefreshRate);
-}
-
-TEST_P(SetFrameRateTest, addChildForParentWithTreeVote) {
- EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1);
-
- const auto& layerFactory = GetParam();
-
- const auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- const auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- const auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
- const auto childOfChild1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
-
- addChild(parent, child1);
- addChild(child1, childOfChild1);
-
- childOfChild1->setFrameRate(FRAME_RATE_VOTE1.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
-
- addChild(parent, child2);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_VOTE1, childOfChild1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
-
- childOfChild1->setFrameRate(FRAME_RATE_NO_VOTE.vote);
- commitTransaction();
- EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_NO_VOTE, childOfChild1->getFrameRateForLayerTree());
- EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
-}
-
-} // namespace
-} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 184dada..e380e19 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -180,6 +180,8 @@
MOCK_METHOD1(onHotplugDisconnect, void(Display));
MOCK_METHOD(Error, setRefreshRateChangedCallbackDebugEnabled, (Display, bool));
MOCK_METHOD(Error, notifyExpectedPresent, (Display, nsecs_t, int32_t));
+ MOCK_METHOD(Error, getDisplayLuts,
+ (Display, std::vector<aidl::android::hardware::graphics::composer3::Lut>*));
};
} // namespace Hwc2::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
index 602bdfc..1eda358 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h
@@ -109,6 +109,8 @@
MOCK_METHOD(hal::Error, getOverlaySupport,
(aidl::android::hardware::graphics::composer3::OverlayProperties *),
(const override));
+ MOCK_METHOD(hal::Error, getDisplayLuts,
+ (std::vector<aidl::android::hardware::graphics::composer3::Lut>*), (override));
};
class Layer : public HWC2::Layer {
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 002fa9f..fdb6f4d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -24,16 +24,10 @@
class MockLayer : public Layer {
public:
MockLayer(SurfaceFlinger* flinger, std::string name)
- : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {
- EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
- .WillOnce(testing::Return(scheduler::FrameRateCompatibility::Default));
- }
+ : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {}
MockLayer(SurfaceFlinger* flinger, std::string name, std::optional<uint32_t> uid)
- : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, uid)) {
- EXPECT_CALL(*this, getDefaultFrameRateCompatibility())
- .WillOnce(testing::Return(scheduler::FrameRateCompatibility::Default));
- }
+ : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {}, uid)) {}
explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}