Merge changes Ibdd75ae6,If628a505 into main
* changes:
s/TestInputListenerMatchers.h/TestEventMatchers.h
Move all matchers from dispatcher tests to TestInputListenerMatchers
diff --git a/libs/binder/RpcTlsUtils.cpp b/libs/binder/RpcTlsUtils.cpp
index f3ca02a..d5c86d7 100644
--- a/libs/binder/RpcTlsUtils.cpp
+++ b/libs/binder/RpcTlsUtils.cpp
@@ -21,6 +21,8 @@
#include "Utils.h"
+#include <limits>
+
namespace android {
namespace {
diff --git a/libs/binder/RpcTransportRaw.cpp b/libs/binder/RpcTransportRaw.cpp
index f3575cc..ddbcb57 100644
--- a/libs/binder/RpcTransportRaw.cpp
+++ b/libs/binder/RpcTransportRaw.cpp
@@ -79,7 +79,7 @@
altPoll);
}
- virtual bool isWaiting() { return mSocket.isInPollingState(); }
+ bool isWaiting() override { return mSocket.isInPollingState(); }
private:
android::RpcTransportFd mSocket;
@@ -88,7 +88,8 @@
// RpcTransportCtx with TLS disabled.
class RpcTransportCtxRaw : public RpcTransportCtx {
public:
- std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd socket, FdTrigger*) const {
+ std::unique_ptr<RpcTransport> newTransport(android::RpcTransportFd socket,
+ FdTrigger*) const override {
return std::make_unique<RpcTransportRaw>(std::move(socket));
}
std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override { return {}; }
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 785f6ce..efb09e9 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -292,7 +292,7 @@
const std::optional<android::base::function_ref<status_t()>>& altPoll,
std::vector<std::variant<base::unique_fd, base::borrowed_fd>>* ancillaryFds) override;
- bool isWaiting() { return mSocket.isInPollingState(); };
+ bool isWaiting() override { return mSocket.isInPollingState(); };
private:
android::RpcTransportFd mSocket;
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
index 2d05fb2..c432b3a 100644
--- a/libs/binder/Stability.cpp
+++ b/libs/binder/Stability.cpp
@@ -75,7 +75,7 @@
Stability::Level Stability::getLocalLevel() {
#ifdef __ANDROID_APEX__
-#error APEX can't use libbinder (must use libbinder_ndk)
+#error "APEX can't use libbinder (must use libbinder_ndk)"
#endif
#ifdef __ANDROID_VNDK__
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index a5c6094..28fb9f1 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -21,6 +21,7 @@
#include <utils/Mutex.h>
#include <map>
+#include <optional>
#include <unordered_map>
#include <variant>
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 4e231ed..45e5ace 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -17,7 +17,9 @@
#pragma once
#include <array>
+#include <limits>
#include <map> // for legacy reasons
+#include <optional>
#include <string>
#include <type_traits>
#include <variant>
diff --git a/libs/binder/include/binder/RpcServer.h b/libs/binder/include/binder/RpcServer.h
index b804f7b..2153f16 100644
--- a/libs/binder/include/binder/RpcServer.h
+++ b/libs/binder/include/binder/RpcServer.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <bitset>
#include <mutex>
#include <thread>
diff --git a/libs/binder/include/binder/RpcThreads.h b/libs/binder/include/binder/RpcThreads.h
index 8abf04e..b80d116 100644
--- a/libs/binder/include/binder/RpcThreads.h
+++ b/libs/binder/include/binder/RpcThreads.h
@@ -19,6 +19,7 @@
#include <android-base/threads.h>
+#include <condition_variable>
#include <functional>
#include <memory>
#include <thread>
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index ed53891..18769b1 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -31,6 +31,7 @@
#include <android/binder_parcel.h>
#include <android/binder_status.h>
#include <assert.h>
+#include <string.h>
#include <unistd.h>
#include <cstddef>
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 6d1dfe8..aab1276 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -58,7 +58,7 @@
],
export_shared_lib_headers: [
- "android.hardware.graphics.common-V4-ndk",
+ "android.hardware.graphics.common-V5-ndk",
"android.hardware.graphics.mapper@4.0",
"libhidlbase",
],
diff --git a/libs/gralloc/types/Gralloc4.cpp b/libs/gralloc/types/Gralloc4.cpp
index 61e6657..ce35906 100644
--- a/libs/gralloc/types/Gralloc4.cpp
+++ b/libs/gralloc/types/Gralloc4.cpp
@@ -1307,6 +1307,10 @@
return "SitedInterstitial";
case ChromaSiting::COSITED_HORIZONTAL:
return "CositedHorizontal";
+ case ChromaSiting::COSITED_VERTICAL:
+ return "CositedVertical";
+ case ChromaSiting::COSITED_BOTH:
+ return "CositedBoth";
}
}
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 9618502..9893c71 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -31,10 +31,13 @@
#include <gui/test/CallbackUtils.h>
#include <private/gui/ComposerService.h>
#include <private/gui/ComposerServiceAIDL.h>
+#include <tests/utils/ScreenshotUtils.h>
#include <ui/DisplayMode.h>
#include <ui/DisplayState.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Size.h>
#include <ui/Transform.h>
#include <gtest/gtest.h>
@@ -197,18 +200,23 @@
ALOGD("Display: %dx%d orientation:%d", mDisplayWidth, mDisplayHeight,
displayState.orientation);
+ mRootSurfaceControl = mClient->createSurface(String8("RootTestSurface"), mDisplayWidth,
+ mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+
+ t.setLayerStack(mRootSurfaceControl, ui::DEFAULT_LAYER_STACK)
+ .setLayer(mRootSurfaceControl, std::numeric_limits<int32_t>::max())
+ .show(mRootSurfaceControl)
+ .apply();
+
mSurfaceControl = mClient->createSurface(String8("TestSurface"), mDisplayWidth,
mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState,
- /*parent*/ nullptr);
- t.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
- .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
- .show(mSurfaceControl)
- .setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
- .apply();
+ /*parent*/ mRootSurfaceControl->getHandle());
- mCaptureArgs.displayToken = mDisplayToken;
- mCaptureArgs.dataspace = ui::Dataspace::V0_SRGB;
+ mCaptureArgs.sourceCrop = Rect(ui::Size(mDisplayWidth, mDisplayHeight));
+ mCaptureArgs.layerHandle = mRootSurfaceControl->getHandle();
}
void setUpProducer(BLASTBufferQueueHelper& adapter, sp<IGraphicBufferProducer>& producer,
@@ -295,21 +303,6 @@
captureBuf->unlock();
}
- static status_t captureDisplay(DisplayCaptureArgs& captureArgs,
- ScreenCaptureResults& captureResults) {
- const auto sf = ComposerServiceAIDL::getComposerService();
- SurfaceComposerClient::Transaction().apply(true);
-
- const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- binder::Status status = sf->captureDisplay(captureArgs, captureListener);
- status_t err = gui::aidl_utils::statusTFromBinderStatus(status);
- if (err != NO_ERROR) {
- return err;
- }
- captureResults = captureListener->waitForResults();
- return fenceStatus(captureResults.fenceResult);
- }
-
void queueBuffer(sp<IGraphicBufferProducer> igbp, uint8_t r, uint8_t g, uint8_t b,
nsecs_t presentTimeDelay) {
int slot;
@@ -342,11 +335,12 @@
sp<IBinder> mDisplayToken;
sp<SurfaceControl> mSurfaceControl;
+ sp<SurfaceControl> mRootSurfaceControl;
uint32_t mDisplayWidth;
uint32_t mDisplayHeight;
- DisplayCaptureArgs mCaptureArgs;
+ LayerCaptureArgs mCaptureArgs;
ScreenCaptureResults mCaptureResults;
sp<CountProducerListener> mProducerListener;
};
@@ -364,7 +358,9 @@
BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
sp<SurfaceControl> updateSurface =
mClient->createSurface(String8("UpdateTest"), mDisplayWidth / 2, mDisplayHeight / 2,
- PIXEL_FORMAT_RGBA_8888);
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ mRootSurfaceControl->getHandle());
adapter.update(updateSurface, mDisplayWidth / 2, mDisplayHeight / 2);
ASSERT_EQ(updateSurface, adapter.getSurfaceControl());
sp<IGraphicBufferProducer> igbProducer;
@@ -451,7 +447,7 @@
Transaction().apply(true /* synchronous */);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -536,7 +532,7 @@
Transaction().apply(true /* synchronous */);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b,
@@ -552,16 +548,6 @@
(mDisplayWidth < mDisplayHeight) ? mDisplayWidth / 2 : mDisplayHeight / 2;
int32_t finalCropSideLength = bufferSideLength / 2;
- auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceEffect);
- ASSERT_NE(nullptr, bg.get());
- Transaction t;
- t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
- .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
- .setColor(bg, half3{0, 0, 0})
- .setLayer(bg, 0)
- .apply();
-
BLASTBufferQueueHelper adapter(mSurfaceControl, bufferSideLength, bufferSideLength);
sp<IGraphicBufferProducer> igbProducer;
setUpProducer(adapter, igbProducer);
@@ -597,7 +583,7 @@
Transaction().apply(true /* synchronous */);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(checkScreenCapture(r, g, b,
{10, 10, (int32_t)bufferSideLength - 10,
(int32_t)bufferSideLength - 10}));
@@ -608,17 +594,6 @@
}
TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToBufferSize) {
- // add black background
- auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceEffect);
- ASSERT_NE(nullptr, bg.get());
- Transaction t;
- t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
- .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
- .setColor(bg, half3{0, 0, 0})
- .setLayer(bg, 0)
- .apply();
-
Rect windowSize(1000, 1000);
Rect bufferSize(windowSize);
Rect bufferCrop(200, 200, 700, 700);
@@ -661,7 +636,7 @@
// ensure the buffer queue transaction has been committed
Transaction().apply(true /* synchronous */);
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
// Verify cropped region is scaled correctly.
ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490}));
@@ -676,17 +651,6 @@
}
TEST_F(BLASTBufferQueueTest, ScaleCroppedBufferToWindowSize) {
- // add black background
- auto bg = mClient->createSurface(String8("BGTest"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceEffect);
- ASSERT_NE(nullptr, bg.get());
- Transaction t;
- t.setLayerStack(bg, ui::DEFAULT_LAYER_STACK)
- .setCrop(bg, Rect(0, 0, mDisplayWidth, mDisplayHeight))
- .setColor(bg, half3{0, 0, 0})
- .setLayer(bg, 0)
- .apply();
-
Rect windowSize(1000, 1000);
Rect bufferSize(500, 500);
Rect bufferCrop(100, 100, 350, 350);
@@ -729,7 +693,7 @@
// ensure the buffer queue transaction has been committed
Transaction().apply(true /* synchronous */);
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
// Verify cropped region is scaled correctly.
ASSERT_NO_FATAL_FAILURE(checkScreenCapture(255, 0, 0, {10, 10, 490, 490}));
ASSERT_NO_FATAL_FAILURE(checkScreenCapture(0, 255, 0, {10, 510, 490, 990}));
@@ -779,7 +743,7 @@
Transaction().apply(true /* synchronous */);
}
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b,
@@ -815,7 +779,7 @@
Transaction().apply(true /* synchronous */);
}
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
// verify we still scale the buffer to the new size (half the screen height)
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b,
@@ -850,12 +814,12 @@
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is green
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(0, 255, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
mProducerListener->waitOnNumberReleased(1);
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -895,7 +859,7 @@
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -943,7 +907,7 @@
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -993,7 +957,7 @@
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -1051,7 +1015,7 @@
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -1084,13 +1048,13 @@
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is blue
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(0, 0, 255, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
mProducerListener->waitOnNumberReleased(2);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(255, 0, 0, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
}
@@ -1186,7 +1150,7 @@
CallbackData callbackData;
transactionCallback.getCallbackData(&callbackData);
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
sync.apply();
@@ -1205,7 +1169,7 @@
mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight,
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState,
- /*parent*/ nullptr);
+ /*parent*/ mRootSurfaceControl->getHandle());
Transaction()
.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
@@ -1230,7 +1194,7 @@
CallbackData callbackData;
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(255, 0, 0,
{0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
@@ -1248,7 +1212,7 @@
mClient->createSurface(String8("TestSurface"), mDisplayWidth, mDisplayHeight,
PIXEL_FORMAT_RGBA_8888,
ISurfaceComposerClient::eFXSurfaceBufferState,
- /*parent*/ nullptr);
+ /*parent*/ mRootSurfaceControl->getHandle());
Transaction()
.setLayerStack(mSurfaceControl, ui::DEFAULT_LAYER_STACK)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
@@ -1273,7 +1237,7 @@
CallbackData callbackData;
transactionCallback.getCallbackData(&callbackData);
// capture screen and verify that it is red
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
ASSERT_NO_FATAL_FAILURE(
checkScreenCapture(255, 0, 0,
{0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight}));
@@ -1406,7 +1370,7 @@
ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
Transaction().apply(true /* synchronous */);
- ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults));
+ ASSERT_EQ(NO_ERROR, ScreenCapture::captureLayers(mCaptureArgs, mCaptureResults));
switch (tr) {
case ui::Transform::ROT_0:
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index e8575a6..6302ff5 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -34,3 +34,10 @@
description: "Set to true to enable multi-device input: touch and stylus can be active at the same time, but in different windows"
bug: "211379801"
}
+
+flag {
+ name: "a11y_crash_on_inconsistent_event_stream"
+ namespace: "accessibility"
+ description: "Brings back fatal logging for inconsistent event streams originating from accessibility."
+ bug: "299977100"
+}
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 9fa5569..47a4bfc 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -456,6 +456,7 @@
* Adobe RGB
*
* Use full range, gamma 2.2 transfer and Adobe RGB primaries
+ *
* Note: Application is responsible for gamma encoding the data as
* a 2.2 gamma encoding is not supported in HW.
*/
@@ -493,7 +494,7 @@
*
* Ultra High-definition television
*
- * Use full range, BT.709 transfer and BT2020 standard
+ * Use full range, SMPTE 170M transfer and BT2020 standard
*/
ADATASPACE_BT2020 = 147193856, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
@@ -502,7 +503,7 @@
*
* High-definition television
*
- * Use limited range, BT.709 transfer and BT.709 standard.
+ * Use limited range, SMPTE 170M transfer and BT.709 standard.
*/
ADATASPACE_BT709 = 281083904, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
@@ -512,6 +513,7 @@
* Digital Cinema DCI-P3
*
* Use full range, gamma 2.6 transfer and D65 DCI-P3 standard
+ *
* Note: Application is responsible for gamma encoding the data as
* a 2.6 gamma encoding is not supported in HW.
*/
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 28aa4dd..8ac0af4 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -28,6 +28,7 @@
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/ShadowSettings.h>
#include <ui/StretchEffect.h>
#include <ui/Transform.h>
@@ -97,36 +98,6 @@
half3 solidColor = half3(0.0f, 0.0f, 0.0f);
};
-/*
- * Contains the configuration for the shadows drawn by single layer. Shadow follows
- * material design guidelines.
- */
-struct ShadowSettings {
- // Boundaries of the shadow.
- FloatRect boundaries = FloatRect();
-
- // Color to the ambient shadow. The alpha is premultiplied.
- vec4 ambientColor = vec4();
-
- // Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow
- // depends on the light position.
- vec4 spotColor = vec4();
-
- // Position of the light source used to cast the spot shadow.
- vec3 lightPos = vec3();
-
- // Radius of the spot light source. Smaller radius will have sharper edges,
- // larger radius will have softer shadows
- float lightRadius = 0.f;
-
- // Length of the cast shadow. If length is <= 0.f no shadows will be drawn.
- float length = 0.f;
-
- // If true fill in the casting layer is translucent and the shadow needs to fill the bounds.
- // Otherwise the shadow will only be drawn around the edges of the casting layer.
- bool casterIsTranslucent = false;
-};
-
// The settings that RenderEngine requires for correctly rendering a Layer.
struct LayerSettings {
// Geometry information
@@ -194,17 +165,6 @@
return lhs.buffer == rhs.buffer && lhs.solidColor == rhs.solidColor;
}
-static inline bool operator==(const ShadowSettings& lhs, const ShadowSettings& rhs) {
- return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor &&
- lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos &&
- lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length &&
- lhs.casterIsTranslucent == rhs.casterIsTranslucent;
-}
-
-static inline bool operator!=(const ShadowSettings& lhs, const ShadowSettings& rhs) {
- return !(operator==(lhs, rhs));
-}
-
static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs) {
if (lhs.blurRegions.size() != rhs.blurRegions.size()) {
return false;
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 7dde716..6023808 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -403,7 +403,7 @@
}
void expectShadowColor(const renderengine::LayerSettings& castingLayer,
- const renderengine::ShadowSettings& shadow, const ubyte4& casterColor,
+ const ShadowSettings& shadow, const ubyte4& casterColor,
const ubyte4& backgroundColor) {
const Rect casterRect(castingLayer.geometry.boundaries);
Region casterRegion = Region(casterRect);
@@ -443,8 +443,7 @@
backgroundColor.a);
}
- void expectShadowColorWithoutCaster(const FloatRect& casterBounds,
- const renderengine::ShadowSettings& shadow,
+ void expectShadowColorWithoutCaster(const FloatRect& casterBounds, const ShadowSettings& shadow,
const ubyte4& backgroundColor) {
const float shadowInset = shadow.length * -1.0f;
const Rect casterRect(casterBounds);
@@ -463,9 +462,9 @@
backgroundColor.a);
}
- static renderengine::ShadowSettings getShadowSettings(const vec2& casterPos, float shadowLength,
- bool casterIsTranslucent) {
- renderengine::ShadowSettings shadow;
+ static ShadowSettings getShadowSettings(const vec2& casterPos, float shadowLength,
+ bool casterIsTranslucent) {
+ ShadowSettings shadow;
shadow.ambientColor = {0.0f, 0.0f, 0.0f, 0.039f};
shadow.spotColor = {0.0f, 0.0f, 0.0f, 0.19f};
shadow.lightPos = vec3(casterPos.x, casterPos.y, 0);
@@ -602,12 +601,10 @@
void fillGreenColorBufferThenClearRegion();
template <typename SourceVariant>
- void drawShadow(const renderengine::LayerSettings& castingLayer,
- const renderengine::ShadowSettings& shadow, const ubyte4& casterColor,
- const ubyte4& backgroundColor);
+ void drawShadow(const renderengine::LayerSettings& castingLayer, const ShadowSettings& shadow,
+ const ubyte4& casterColor, const ubyte4& backgroundColor);
- void drawShadowWithoutCaster(const FloatRect& castingBounds,
- const renderengine::ShadowSettings& shadow,
+ void drawShadowWithoutCaster(const FloatRect& castingBounds, const ShadowSettings& shadow,
const ubyte4& backgroundColor);
// Tonemaps grey values from sourceDataspace -> Display P3 and checks that GPU and CPU
@@ -1337,8 +1334,8 @@
template <typename SourceVariant>
void RenderEngineTest::drawShadow(const renderengine::LayerSettings& castingLayer,
- const renderengine::ShadowSettings& shadow,
- const ubyte4& casterColor, const ubyte4& backgroundColor) {
+ const ShadowSettings& shadow, const ubyte4& casterColor,
+ const ubyte4& backgroundColor) {
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
settings.physicalDisplay = fullscreenRect();
@@ -1374,7 +1371,7 @@
}
void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds,
- const renderengine::ShadowSettings& shadow,
+ const ShadowSettings& shadow,
const ubyte4& backgroundColor) {
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -2103,9 +2100,8 @@
const float shadowLength = 5.0f;
Rect casterBounds(DEFAULT_DISPLAY_WIDTH / 3.0f, DEFAULT_DISPLAY_HEIGHT / 3.0f);
casterBounds.offsetBy(shadowLength + 1, shadowLength + 1);
- renderengine::ShadowSettings settings =
- getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
- false /* casterIsTranslucent */);
+ ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top),
+ shadowLength, false /* casterIsTranslucent */);
drawShadowWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor);
expectShadowColorWithoutCaster(casterBounds.toFloatRect(), settings, backgroundColor);
@@ -2127,9 +2123,8 @@
renderengine::LayerSettings castingLayer;
castingLayer.geometry.boundaries = casterBounds.toFloatRect();
castingLayer.alpha = 1.0f;
- renderengine::ShadowSettings settings =
- getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
- false /* casterIsTranslucent */);
+ ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top),
+ shadowLength, false /* casterIsTranslucent */);
drawShadow<ColorSourceVariant>(castingLayer, settings, casterColor, backgroundColor);
expectShadowColor(castingLayer, settings, casterColor, backgroundColor);
@@ -2152,9 +2147,8 @@
castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
castingLayer.geometry.boundaries = casterBounds.toFloatRect();
castingLayer.alpha = 1.0f;
- renderengine::ShadowSettings settings =
- getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
- false /* casterIsTranslucent */);
+ ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top),
+ shadowLength, false /* casterIsTranslucent */);
drawShadow<ColorSourceVariant>(castingLayer, settings, casterColor, backgroundColor);
expectShadowColor(castingLayer, settings, casterColor, backgroundColor);
@@ -2177,9 +2171,8 @@
castingLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
castingLayer.geometry.boundaries = casterBounds.toFloatRect();
castingLayer.alpha = 1.0f;
- renderengine::ShadowSettings settings =
- getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
- false /* casterIsTranslucent */);
+ ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top),
+ shadowLength, false /* casterIsTranslucent */);
drawShadow<BufferSourceVariant<ForceOpaqueBufferVariant>>(castingLayer, settings, casterColor,
backgroundColor);
@@ -2204,9 +2197,8 @@
castingLayer.geometry.roundedCornersRadius = {3.0f, 3.0f};
castingLayer.geometry.roundedCornersCrop = casterBounds.toFloatRect();
castingLayer.alpha = 1.0f;
- renderengine::ShadowSettings settings =
- getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
- false /* casterIsTranslucent */);
+ ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top),
+ shadowLength, false /* casterIsTranslucent */);
drawShadow<BufferSourceVariant<ForceOpaqueBufferVariant>>(castingLayer, settings, casterColor,
backgroundColor);
@@ -2227,9 +2219,8 @@
renderengine::LayerSettings castingLayer;
castingLayer.geometry.boundaries = casterBounds.toFloatRect();
castingLayer.alpha = 0.5f;
- renderengine::ShadowSettings settings =
- getShadowSettings(vec2(casterBounds.left, casterBounds.top), shadowLength,
- true /* casterIsTranslucent */);
+ ShadowSettings settings = getShadowSettings(vec2(casterBounds.left, casterBounds.top),
+ shadowLength, true /* casterIsTranslucent */);
drawShadow<BufferSourceVariant<RelaxOpaqueBufferVariant>>(castingLayer, settings, casterColor,
backgroundColor);
diff --git a/libs/ui/include/ui/ShadowSettings.h b/libs/ui/include/ui/ShadowSettings.h
new file mode 100644
index 0000000..c0b83b8
--- /dev/null
+++ b/libs/ui/include/ui/ShadowSettings.h
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <math/vec4.h>
+#include "FloatRect.h"
+
+namespace android {
+
+/*
+ * Contains the configuration for the shadows drawn by single layer. Shadow follows
+ * material design guidelines.
+ */
+struct ShadowSettings {
+ // Boundaries of the shadow.
+ FloatRect boundaries = FloatRect();
+
+ // Color to the ambient shadow. The alpha is premultiplied.
+ vec4 ambientColor = vec4();
+
+ // Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow
+ // depends on the light position.
+ vec4 spotColor = vec4();
+
+ // Position of the light source used to cast the spot shadow.
+ vec3 lightPos = vec3();
+
+ // Radius of the spot light source. Smaller radius will have sharper edges,
+ // larger radius will have softer shadows
+ float lightRadius = 0.f;
+
+ // Length of the cast shadow. If length is <= 0.f no shadows will be drawn.
+ float length = 0.f;
+
+ // If true fill in the casting layer is translucent and the shadow needs to fill the bounds.
+ // Otherwise the shadow will only be drawn around the edges of the casting layer.
+ bool casterIsTranslucent = false;
+};
+
+static inline bool operator==(const ShadowSettings& lhs, const ShadowSettings& rhs) {
+ return lhs.boundaries == rhs.boundaries && lhs.ambientColor == rhs.ambientColor &&
+ lhs.spotColor == rhs.spotColor && lhs.lightPos == rhs.lightPos &&
+ lhs.lightRadius == rhs.lightRadius && lhs.length == rhs.length &&
+ lhs.casterIsTranslucent == rhs.casterIsTranslucent;
+}
+
+static inline bool operator!=(const ShadowSettings& lhs, const ShadowSettings& rhs) {
+ return !(operator==(lhs, rhs));
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1589278..27b86bd 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -25,6 +25,7 @@
#include <android-base/stringprintf.h>
#include <android/os/IInputConstants.h>
#include <binder/Binder.h>
+#include <com_android_input_flags.h>
#include <ftl/enum.h>
#include <log/log_event_list.h>
#if defined(__ANDROID__)
@@ -67,6 +68,7 @@
using android::gui::WindowInfoHandle;
using android::os::InputEventInjectionResult;
using android::os::InputEventInjectionSync;
+namespace input_flags = com::android::input::flags;
namespace android::inputdispatcher {
@@ -670,11 +672,11 @@
// This pointer was already sent to the window. Use ACTION_HOVER_MOVE.
if (CC_UNLIKELY(maskedAction != AMOTION_EVENT_ACTION_HOVER_MOVE)) {
android::base::LogSeverity severity = android::base::LogSeverity::FATAL;
- if (entry.flags & AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT) {
+ if (!input_flags::a11y_crash_on_inconsistent_event_stream() &&
+ entry.flags & AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT) {
// The Accessibility injected touch exploration event stream
// has known inconsistencies, so log ERROR instead of
// crashing the device with FATAL.
- // TODO(b/299977100): Move a11y severity back to FATAL.
severity = android::base::LogSeverity::ERROR;
}
LOG(severity) << "Expected ACTION_HOVER_MOVE instead of " << entry.getDescription();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 0922354..64e8825 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -93,6 +93,7 @@
},
},
static_libs: [
+ "libflagtest",
"libc++fs",
"libgmock",
],
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 561a81b..2f63b2a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -24,7 +24,9 @@
#include <android-base/stringprintf.h>
#include <android-base/thread_annotations.h>
#include <binder/Binder.h>
+#include <com_android_input_flags.h>
#include <fcntl.h>
+#include <flag_macros.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <input/Input.h>
@@ -3770,7 +3772,9 @@
/**
* Test that invalid HOVER events sent by accessibility do not cause a fatal crash.
*/
-TEST_F(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash) {
+TEST_F_WITH_FLAGS(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash,
+ REQUIRES_FLAGS_DISABLED(ACONFIG_FLAG(com::android::input::flags,
+ a11y_crash_on_inconsistent_event_stream))) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 35ca3a5..11759b8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -26,6 +26,7 @@
#include <ui/LayerStack.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/ShadowSettings.h>
#include <ui/Transform.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -132,8 +133,7 @@
// The bounds of the layer in layer local coordinates
FloatRect geomLayerBounds;
- // length of the shadow in screen space
- float shadowRadius{0.f};
+ ShadowSettings shadowSettings;
// List of regions that require blur
std::vector<BlurRegion> blurRegions;
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
index 426cc57..2d10866 100644
--- a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -68,7 +68,7 @@
dumpVal(out, "geomLayerBounds", geomLayerBounds);
out.append(" ");
- dumpVal(out, "shadowRadius", shadowRadius);
+ dumpVal(out, "shadowLength", shadowSettings.length);
out.append("\n ");
dumpVal(out, "blend", toString(blendMode), blendMode);
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 78c23da..fa3733b 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -588,10 +588,10 @@
const Rect visibleRect(tr.transform(layerFEState->geomLayerBounds));
visibleRegion.set(visibleRect);
- if (layerFEState->shadowRadius > 0.0f) {
+ if (layerFEState->shadowSettings.length > 0.0f) {
// if the layer casts a shadow, offset the layers visible region and
// calculate the shadow region.
- const auto inset = static_cast<int32_t>(ceilf(layerFEState->shadowRadius) * -1.0f);
+ const auto inset = static_cast<int32_t>(ceilf(layerFEState->shadowSettings.length) * -1.0f);
Rect visibleRectWithShadows(visibleRect);
visibleRectWithShadows.inset(inset, inset, inset, inset);
visibleRegion.set(visibleRectWithShadows);
@@ -967,7 +967,7 @@
case ui::Dataspace::BT2020_ITU_HLG:
bestDataSpace = ui::Dataspace::DISPLAY_P3;
// When there's mixed PQ content and HLG content, we set the HDR
- // data space to be BT2020_PQ and convert HLG to PQ.
+ // data space to be BT2020_HLG and convert PQ to HLG.
if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) {
*outHdrDataSpace = ui::Dataspace::BT2020_HLG;
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index fe56969..7fe3369 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -222,8 +222,8 @@
// Some HWCs may clip client composited input to its displayFrame. Make sure
// that this does not cut off the shadow.
- if (layerState.forceClientComposition && layerState.shadowRadius > 0.0f) {
- const auto outset = layerState.shadowRadius;
+ if (layerState.forceClientComposition && layerState.shadowSettings.length > 0.0f) {
+ const auto outset = layerState.shadowSettings.length;
geomLayerBounds.left -= outset;
geomLayerBounds.top -= outset;
geomLayerBounds.right += outset;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 630906a..1c54469 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -334,7 +334,7 @@
TEST_F(OutputLayerDisplayFrameTest, shadowExpandsDisplayFrame) {
const int kShadowRadius = 5;
- mLayerFEState.shadowRadius = kShadowRadius;
+ mLayerFEState.shadowSettings.length = kShadowRadius;
mLayerFEState.forceClientComposition = true;
mLayerFEState.geomLayerBounds = FloatRect{100.f, 100.f, 200.f, 200.f};
@@ -345,7 +345,7 @@
TEST_F(OutputLayerDisplayFrameTest, shadowExpandsDisplayFrame_onlyIfForcingClientComposition) {
const int kShadowRadius = 5;
- mLayerFEState.shadowRadius = kShadowRadius;
+ mLayerFEState.shadowSettings.length = kShadowRadius;
mLayerFEState.forceClientComposition = false;
mLayerFEState.geomLayerBounds = FloatRect{100.f, 100.f, 200.f, 200.f};
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index ee6998a..cdcb68d 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -1830,7 +1830,7 @@
ui::Transform translate;
translate.set(50, 50);
mLayer.layerFEState.geomLayerTransform = translate;
- mLayer.layerFEState.shadowRadius = 10.0f;
+ mLayer.layerFEState.shadowSettings.length = 10.0f;
mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500));
// half of the layer including the casting shadow is covered and opaque
@@ -1872,7 +1872,7 @@
ui::Transform translate;
translate.set(50, 50);
mLayer.layerFEState.geomLayerTransform = translate;
- mLayer.layerFEState.shadowRadius = 10.0f;
+ mLayer.layerFEState.shadowSettings.length = 10.0f;
mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500));
// Casting layer is covered by an opaque region leaving only part of its shadow to be drawn
@@ -1897,7 +1897,7 @@
ui::Transform translate;
translate.set(50, 50);
mLayer.layerFEState.geomLayerTransform = translate;
- mLayer.layerFEState.shadowRadius = 10.0f;
+ mLayer.layerFEState.shadowSettings.length = 10.0f;
mCoverageState.dirtyRegion = Region(Rect(0, 0, 500, 500));
// Casting layer and its shadows are covered by an opaque region
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index f9c8e81..7a85da0 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -382,7 +382,6 @@
sidebandStream = requested.sidebandStream;
}
if (forceUpdate || requested.what & layer_state_t::eShadowRadiusChanged) {
- shadowRadius = requested.shadowRadius;
shadowSettings.length = requested.shadowRadius;
}
if (forceUpdate || requested.what & layer_state_t::eFrameRateSelectionPriority) {
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index a1c72a9..80a51ea 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -69,7 +69,6 @@
RoundedCornerState roundedCorner;
FloatRect transformedBounds;
Rect transformedBoundsWithoutTransparentRegion;
- renderengine::ShadowSettings shadowSettings;
bool premultipliedAlpha;
ui::Transform parentTransform;
Rect bufferSize;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 55be398..03c0993 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -353,7 +353,7 @@
snapshot.isSecure = false;
snapshot.color.a = 1.0_hf;
snapshot.colorTransformIsIdentity = true;
- snapshot.shadowRadius = 0.f;
+ snapshot.shadowSettings.length = 0.f;
snapshot.layerMetadata.mMap.clear();
snapshot.relativeLayerMetadata.mMap.clear();
snapshot.inputInfo.touchOcclusionMode = gui::TouchOcclusionMode::BLOCK_UNTRUSTED;
@@ -990,9 +990,12 @@
}
void LayerSnapshotBuilder::updateShadows(LayerSnapshot& snapshot, const RequestedLayerState&,
- const renderengine::ShadowSettings& globalShadowSettings) {
- if (snapshot.shadowRadius > 0.f) {
- snapshot.shadowSettings = globalShadowSettings;
+ const ShadowSettings& globalShadowSettings) {
+ if (snapshot.shadowSettings.length > 0.f) {
+ snapshot.shadowSettings.ambientColor = globalShadowSettings.ambientColor;
+ snapshot.shadowSettings.spotColor = globalShadowSettings.spotColor;
+ snapshot.shadowSettings.lightPos = globalShadowSettings.lightPos;
+ snapshot.shadowSettings.lightRadius = globalShadowSettings.lightRadius;
// Note: this preserves existing behavior of shadowing the entire layer and not cropping
// it if transparent regions are present. This may not be necessary since shadows are
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index 3d64b36..1506913 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -47,7 +47,7 @@
const DisplayInfos& displays;
// Set to true if there were display changes since last update.
bool displayChanges = false;
- const renderengine::ShadowSettings& globalShadowSettings;
+ const ShadowSettings& globalShadowSettings;
bool supportsBlur = true;
bool forceFullDamage = false;
std::optional<FloatRect> parentCrop = std::nullopt;
@@ -108,7 +108,7 @@
void updateLayerBounds(LayerSnapshot& snapshot, const RequestedLayerState& layerState,
const LayerSnapshot& parentSnapshot, uint32_t displayRotationFlags);
static void updateShadows(LayerSnapshot& snapshot, const RequestedLayerState& requested,
- const renderengine::ShadowSettings& globalShadowSettings);
+ const ShadowSettings& globalShadowSettings);
void updateInput(LayerSnapshot& snapshot, const RequestedLayerState& requested,
const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath& path,
const Args& args);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 5ae2999..2dc8758 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -572,7 +572,7 @@
snapshot->outputFilter = getOutputFilter();
snapshot->isVisible = isVisible();
snapshot->isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
- snapshot->shadowRadius = mEffectiveShadowRadius;
+ snapshot->shadowSettings.length = mEffectiveShadowRadius;
snapshot->contentDirty = contentDirty;
contentDirty = false;
@@ -1267,7 +1267,8 @@
return parentFrameRate;
}();
- *transactionNeeded |= setFrameRateForLayerTreeLegacy(frameRate);
+ auto now = systemTime();
+ *transactionNeeded |= setFrameRateForLayerTreeLegacy(frameRate, now);
// The frame rate is propagated to the children
bool childrenHaveFrameRate = false;
@@ -1283,7 +1284,8 @@
// layer as NoVote to allow the children to control the refresh rate
if (!frameRate.isValid() && childrenHaveFrameRate) {
*transactionNeeded |=
- setFrameRateForLayerTreeLegacy(FrameRate(Fps(), FrameRateCompatibility::NoVote));
+ setFrameRateForLayerTreeLegacy(FrameRate(Fps(), FrameRateCompatibility::NoVote),
+ now);
}
// We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes for
@@ -1492,7 +1494,7 @@
addSurfaceFrameDroppedForBuffer(surfaceFrame, postTime);
}
-bool Layer::setFrameRateForLayerTreeLegacy(FrameRate frameRate) {
+bool Layer::setFrameRateForLayerTreeLegacy(FrameRate frameRate, nsecs_t now) {
if (mDrawingState.frameRateForLayerTree == frameRate) {
return false;
}
@@ -1506,19 +1508,20 @@
setTransactionFlags(eTransactionNeeded);
mFlinger->mScheduler
- ->recordLayerHistory(sequence, getLayerProps(), systemTime(),
+ ->recordLayerHistory(sequence, getLayerProps(), now, now,
scheduler::LayerHistory::LayerUpdateType::SetFrameRate);
return true;
}
-bool Layer::setFrameRateForLayerTree(FrameRate frameRate, const scheduler::LayerProps& layerProps) {
+bool Layer::setFrameRateForLayerTree(FrameRate frameRate, const scheduler::LayerProps& layerProps,
+ nsecs_t now) {
if (mDrawingState.frameRateForLayerTree == frameRate) {
return false;
}
mDrawingState.frameRateForLayerTree = frameRate;
mFlinger->mScheduler
- ->recordLayerHistory(sequence, layerProps, systemTime(),
+ ->recordLayerHistory(sequence, layerProps, now, now,
scheduler::LayerHistory::LayerUpdateType::SetFrameRate);
return true;
}
@@ -3225,7 +3228,7 @@
mOwnerUid, postTime, getGameMode());
if (mFlinger->mLegacyFrontEndEnabled) {
- recordLayerHistoryBufferUpdate(getLayerProps());
+ recordLayerHistoryBufferUpdate(getLayerProps(), systemTime());
}
setFrameTimelineVsyncForBufferTransaction(info, postTime);
@@ -3256,7 +3259,7 @@
mDrawingState.isAutoTimestamp = isAutoTimestamp;
}
-void Layer::recordLayerHistoryBufferUpdate(const scheduler::LayerProps& layerProps) {
+void Layer::recordLayerHistoryBufferUpdate(const scheduler::LayerProps& layerProps, nsecs_t now) {
ATRACE_CALL();
const nsecs_t presentTime = [&] {
if (!mDrawingState.isAutoTimestamp) {
@@ -3310,14 +3313,14 @@
ATRACE_FORMAT_INSTANT("presentIn %s", to_string(presentIn).c_str());
}
- mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime,
+ mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, now,
scheduler::LayerHistory::LayerUpdateType::Buffer);
}
-void Layer::recordLayerHistoryAnimationTx(const scheduler::LayerProps& layerProps) {
+void Layer::recordLayerHistoryAnimationTx(const scheduler::LayerProps& layerProps, nsecs_t now) {
const nsecs_t presentTime =
mDrawingState.isAutoTimestamp ? 0 : mDrawingState.desiredPresentTime;
- mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime,
+ mFlinger->mScheduler->recordLayerHistory(sequence, layerProps, presentTime, now,
scheduler::LayerHistory::LayerUpdateType::AnimationTX);
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 78a3a7c..0b66866 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -908,10 +908,10 @@
void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener,
const sp<GraphicBuffer>& buffer, uint64_t framenumber,
const sp<Fence>& releaseFence);
- bool setFrameRateForLayerTreeLegacy(FrameRate);
- bool setFrameRateForLayerTree(FrameRate, const scheduler::LayerProps&);
- void recordLayerHistoryBufferUpdate(const scheduler::LayerProps&);
- void recordLayerHistoryAnimationTx(const scheduler::LayerProps&);
+ 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(),
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index 97c4145..48a9190 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -310,7 +310,7 @@
void LayerFE::prepareShadowClientComposition(LayerFE::LayerSettings& caster,
const Rect& layerStackRect) const {
- renderengine::ShadowSettings state = mSnapshot->shadowSettings;
+ ShadowSettings state = mSnapshot->shadowSettings;
if (state.length <= 0.f || (state.ambientColor.a <= 0.f && state.spotColor.a <= 0.f)) {
return;
}
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 144e1f5..aa6026e 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -402,7 +402,7 @@
[&]() { return layerInfo->mutable_screen_bounds(); });
LayerProtoHelper::writeToProto(snapshot.roundedCorner.cropRect,
[&]() { return layerInfo->mutable_corner_radius_crop(); });
- layerInfo->set_shadow_radius(snapshot.shadowRadius);
+ layerInfo->set_shadow_radius(snapshot.shadowSettings.length);
layerInfo->set_id(snapshot.uniqueSequence);
layerInfo->set_original_id(snapshot.sequence);
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 40bda83..bac1ec6 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -91,6 +91,7 @@
private:
friend class LayerHistoryTest;
+ friend class LayerHistoryIntegrationTest;
friend class TestableScheduler;
using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>;
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 6286b28..d580b58 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -62,6 +62,7 @@
static constexpr size_t kNumSmallDirtyThreshold = 2;
friend class LayerHistoryTest;
+ friend class LayerHistoryIntegrationTest;
friend class LayerInfoTest;
public:
@@ -264,6 +265,7 @@
private:
friend class LayerHistoryTest;
+ friend class LayerHistoryIntegrationTest;
// Holds the refresh rate when it was calculated
struct RefreshRateData {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 76f1af9..5115c42 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -192,7 +192,8 @@
for (const auto& [id, display] : mDisplays) {
if (id == pacesetterId) continue;
- const FrameTargeter& targeter = *display.targeterPtr;
+ FrameTargeter& targeter = *display.targeterPtr;
+ targeter.beginFrame(beginFrameArgs, *display.schedulePtr);
targets.try_emplace(id, &targeter.target());
}
@@ -206,8 +207,6 @@
if (id == pacesetterId) continue;
FrameTargeter& targeter = *display.targeterPtr;
- targeter.beginFrame(beginFrameArgs, *display.schedulePtr);
-
targeters.try_emplace(id, &targeter);
}
@@ -625,9 +624,9 @@
}
void Scheduler::recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime,
- LayerHistory::LayerUpdateType updateType) {
+ nsecs_t now, LayerHistory::LayerUpdateType updateType) {
if (pacesetterSelectorPtr()->canSwitch()) {
- mLayerHistory.record(id, layerProps, presentTime, systemTime(), updateType);
+ mLayerHistory.record(id, layerProps, presentTime, now, updateType);
}
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index e6db654..3441318 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -230,7 +230,7 @@
// Layers are registered on creation, and unregistered when the weak reference expires.
void registerLayer(Layer*);
void recordLayerHistory(int32_t id, const LayerProps& layerProps, nsecs_t presentTime,
- LayerHistory::LayerUpdateType) EXCLUDES(mDisplayLock);
+ nsecs_t now, LayerHistory::LayerUpdateType) EXCLUDES(mDisplayLock);
void setModeChangePending(bool pending);
void setDefaultFrameRateCompatibility(int32_t id, scheduler::FrameRateCompatibility);
void deregisterLayer(Layer*);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fb5872c..2b70301 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2203,44 +2203,46 @@
return mustComposite;
}
-void SurfaceFlinger::updateLayerHistory(const frontend::LayerSnapshot& snapshot) {
- using Changes = frontend::RequestedLayerState::Changes;
- if (snapshot.path.isClone()) {
- return;
- }
+void SurfaceFlinger::updateLayerHistory(nsecs_t now) {
+ for (const auto& snapshot : mLayerSnapshotBuilder.getSnapshots()) {
+ using Changes = frontend::RequestedLayerState::Changes;
+ if (snapshot->path.isClone()) {
+ continue;
+ }
- if (!snapshot.changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation) &&
- (snapshot.clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) == 0) {
- return;
- }
+ if (!snapshot->changes.any(Changes::FrameRate | Changes::Buffer | Changes::Animation) &&
+ (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) == 0) {
+ continue;
+ }
- const auto layerProps = scheduler::LayerProps{
- .visible = snapshot.isVisible,
- .bounds = snapshot.geomLayerBounds,
- .transform = snapshot.geomLayerTransform,
- .setFrameRateVote = snapshot.frameRate,
- .frameRateSelectionPriority = snapshot.frameRateSelectionPriority,
- };
+ const auto layerProps = scheduler::LayerProps{
+ .visible = snapshot->isVisible,
+ .bounds = snapshot->geomLayerBounds,
+ .transform = snapshot->geomLayerTransform,
+ .setFrameRateVote = snapshot->frameRate,
+ .frameRateSelectionPriority = snapshot->frameRateSelectionPriority,
+ };
- auto it = mLegacyLayers.find(snapshot.sequence);
- LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s",
- snapshot.getDebugString().c_str());
+ auto it = mLegacyLayers.find(snapshot->sequence);
+ LOG_ALWAYS_FATAL_IF(it == mLegacyLayers.end(), "Couldnt find layer object for %s",
+ snapshot->getDebugString().c_str());
- if (snapshot.changes.test(Changes::Animation)) {
- it->second->recordLayerHistoryAnimationTx(layerProps);
- }
+ if (snapshot->clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) {
+ mScheduler->setDefaultFrameRateCompatibility(snapshot->sequence,
+ snapshot->defaultFrameRateCompatibility);
+ }
- if (snapshot.clientChanges & layer_state_t::eDefaultFrameRateCompatibilityChanged) {
- mScheduler->setDefaultFrameRateCompatibility(snapshot.sequence,
- snapshot.defaultFrameRateCompatibility);
- }
+ if (snapshot->changes.test(Changes::Animation)) {
+ it->second->recordLayerHistoryAnimationTx(layerProps, now);
+ }
- if (snapshot.changes.test(Changes::FrameRate)) {
- it->second->setFrameRateForLayerTree(snapshot.frameRate, layerProps);
- }
+ if (snapshot->changes.test(Changes::FrameRate)) {
+ it->second->setFrameRateForLayerTree(snapshot->frameRate, layerProps, now);
+ }
- if (snapshot.changes.test(Changes::Buffer)) {
- it->second->recordLayerHistoryBufferUpdate(layerProps);
+ if (snapshot->changes.test(Changes::Buffer)) {
+ it->second->recordLayerHistoryBufferUpdate(layerProps, now);
+ }
}
}
@@ -2379,8 +2381,8 @@
mLayersIdsWithQueuedFrames.emplace(it->second->sequence);
}
+ updateLayerHistory(latchTime);
mLayerSnapshotBuilder.forEachVisibleSnapshot([&](const frontend::LayerSnapshot& snapshot) {
- updateLayerHistory(snapshot);
if (mLayersIdsWithQueuedFrames.find(snapshot.path.id) ==
mLayersIdsWithQueuedFrames.end())
return;
@@ -4832,7 +4834,7 @@
for (const auto& listener : listenerCallbacks) {
mTransactionCallbackInvoker.addEmptyTransaction(listener);
}
-
+ nsecs_t now = systemTime();
uint32_t clientStateFlags = 0;
for (auto& resolvedState : states) {
if (mLegacyFrontEndEnabled) {
@@ -4854,7 +4856,7 @@
.setFrameRateVote = layer->getFrameRateForLayerTree(),
.frameRateSelectionPriority = layer->getFrameRateSelectionPriority(),
};
- layer->recordLayerHistoryAnimationTx(layerProps);
+ layer->recordLayerHistoryAnimationTx(layerProps, now);
}
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a5a2341..cbea312 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -419,7 +419,7 @@
bool colorMatrixChanged = true;
mat4 colorMatrix;
- renderengine::ShadowSettings globalShadowSettings;
+ ShadowSettings globalShadowSettings;
void traverse(const LayerVector::Visitor& visitor) const;
void traverseInZOrder(const LayerVector::Visitor& visitor) const;
@@ -732,7 +732,7 @@
bool& out) REQUIRES(kMainThreadContext);
bool updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed,
bool& out) REQUIRES(kMainThreadContext);
- void updateLayerHistory(const frontend::LayerSnapshot& snapshot);
+ void updateLayerHistory(nsecs_t now);
frontend::Update flushLifecycleUpdates() REQUIRES(kMainThreadContext);
void updateInputFlinger(VsyncId vsyncId, TimePoint frameTime);
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index 23fe8fa..c2d1954 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -56,7 +56,7 @@
frontend::LayerSnapshotBuilder snapshotBuilder;
ui::DisplayMap<ui::LayerStack, frontend::DisplayInfo> displayInfos;
- renderengine::ShadowSettings globalShadowSettings{.ambientColor = {1, 1, 1, 1}};
+ ShadowSettings globalShadowSettings{.ambientColor = {1, 1, 1, 1}};
char value[PROPERTY_VALUE_MAX];
property_get("ro.surface_flinger.supports_background_blur", value, "0");
bool supportsBlur = atoi(value);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index bc27e7e..c99809b 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -77,6 +77,7 @@
"HWComposerTest.cpp",
"OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
+ "LayerHistoryIntegrationTest.cpp",
"LayerInfoTest.cpp",
"LayerMetadataTest.cpp",
"LayerHierarchyTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index d7ac038..d319dcc 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -18,11 +18,14 @@
#include <gtest/gtest.h>
#include <gui/fake/BufferData.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+#include <ui/ShadowSettings.h>
#include "Client.h" // temporarily needed for LayerCreationArgs
#include "FrontEnd/LayerCreationArgs.h"
#include "FrontEnd/LayerHierarchy.h"
#include "FrontEnd/LayerLifecycleManager.h"
+#include "FrontEnd/LayerSnapshotBuilder.h"
namespace android::surfaceflinger::frontend {
@@ -358,6 +361,19 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setDefaultFrameRateCompatibility(uint32_t id, int8_t defaultFrameRateCompatibility) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what =
+ layer_state_t::eDefaultFrameRateCompatibilityChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.defaultFrameRateCompatibility =
+ defaultFrameRateCompatibility;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
void setRoundedCorners(uint32_t id, float radius) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
@@ -384,6 +400,16 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setBuffer(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 /*usage*/));
+ }
+
void setBufferCrop(uint32_t id, const Rect& bufferCrop) {
std::vector<TransactionState> transactions;
transactions.emplace_back();
@@ -406,7 +432,64 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setShadowRadius(uint32_t id, float shadowRadius) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eShadowRadiusChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.shadowRadius = shadowRadius;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
LayerLifecycleManager mLifecycleManager;
};
+class LayerSnapshotTestBase : public LayerHierarchyTestBase {
+protected:
+ LayerSnapshotTestBase() : LayerHierarchyTestBase() {}
+
+ void createRootLayer(uint32_t id) override {
+ LayerHierarchyTestBase::createRootLayer(id);
+ setColor(id);
+ }
+
+ void createLayer(uint32_t id, uint32_t parentId) override {
+ LayerHierarchyTestBase::createLayer(id, parentId);
+ setColor(parentId);
+ }
+
+ void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) override {
+ LayerHierarchyTestBase::mirrorLayer(id, parent, layerToMirror);
+ setColor(id);
+ }
+
+ void update(LayerSnapshotBuilder& snapshotBuilder) {
+ if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) {
+ mHierarchyBuilder.update(mLifecycleManager.getLayers(),
+ mLifecycleManager.getDestroyedLayers());
+ }
+ LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+ .layerLifecycleManager = mLifecycleManager,
+ .includeMetadata = false,
+ .displays = mFrontEndDisplayInfos,
+ .displayChanges = mHasDisplayChanges,
+ .globalShadowSettings = globalShadowSettings,
+ .supportsBlur = true,
+ .supportedLayerGenericMetadata = {},
+ .genericLayerMetadataKeyMap = {}};
+ snapshotBuilder.update(args);
+
+ mLifecycleManager.commitChanges();
+ }
+
+ LayerHierarchyBuilder mHierarchyBuilder{{}};
+
+ DisplayInfos mFrontEndDisplayInfos;
+ bool mHasDisplayChanges = false;
+
+ ShadowSettings globalShadowSettings;
+};
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
new file mode 100644
index 0000000..a462082
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryIntegrationTest.cpp
@@ -0,0 +1,873 @@
+/*
+ * 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 "LayerHistoryIntegrationTest"
+
+#include <Layer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+#include <renderengine/mock/FakeExternalTexture.h>
+
+#include "FpsOps.h"
+#include "LayerHierarchyTest.h"
+#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfo.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockDisplayMode.h"
+#include "mock/MockSchedulerCallback.h"
+
+namespace android::scheduler {
+
+using android::mock::createDisplayMode;
+
+class LayerHistoryIntegrationTest : public surfaceflinger::frontend::LayerSnapshotTestBase {
+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();
+
+ LayerHistoryIntegrationTest() : LayerSnapshotTestBase() {
+ mFlinger.resetScheduler(mScheduler);
+ mLifecycleManager = {};
+ mHierarchyBuilder = {{}};
+ }
+
+ void updateLayerSnapshotsAndLayerHistory(nsecs_t now) {
+ LayerSnapshotTestBase::update(mFlinger.mutableLayerSnapshotBuilder());
+ mFlinger.updateLayerHistory(now);
+ }
+
+ void setBufferWithPresentTime(sp<Layer>& layer, nsecs_t time) {
+ uint32_t sequence = static_cast<uint32_t>(layer->sequence);
+ setBuffer(sequence);
+ layer->setDesiredPresentTime(time, false /*autotimestamp*/);
+ updateLayerSnapshotsAndLayerHistory(time);
+ }
+
+ 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 createLegacyAndFrontedEndLayer(uint32_t sequence) {
+ std::string layerName = "test layer:" + std::to_string(sequence);
+ const auto layer =
+ sp<Layer>::make(LayerCreationArgs{mFlinger.flinger(),
+ nullptr,
+ layerName,
+ 0,
+ {},
+ std::make_optional<uint32_t>(sequence)});
+ mFlinger.injectLegacyLayer(layer);
+ createRootLayer(sequence);
+ return layer;
+ }
+
+ auto destroyLayer(sp<Layer>& layer) {
+ uint32_t sequence = static_cast<uint32_t>(layer->sequence);
+ mFlinger.releaseLegacyLayer(sequence);
+ layer.clear();
+ destroyLayerHandle(sequence);
+ }
+
+ void recordFramesAndExpect(sp<Layer>& layer, nsecs_t& time, Fps frameRate,
+ Fps desiredRefreshRate, int numFrames) {
+ LayerHistory::Summary summary;
+ for (int i = 0; i < numFrames; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += frameRate.getPeriodNsecs();
+
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ 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));
+
+ mock::SchedulerCallback mSchedulerCallback;
+
+ TestableScheduler* mScheduler = new TestableScheduler(mSelector, mSchedulerCallback);
+
+ TestableSurfaceFlinger mFlinger;
+};
+
+namespace {
+
+TEST_F(LayerHistoryIntegrationTest, singleLayerNoVoteDefaultCompatibility) {
+ 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());
+
+ setBuffer(1);
+ setDefaultFrameRateCompatibility(1, ANATIVEWINDOW_FRAME_RATE_NO_VOTE);
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(1u, activeLayerCount());
+}
+
+TEST_F(LayerHistoryIntegrationTest, singleLayerMinVoteDefaultCompatibility) {
+ createLegacyAndFrontedEndLayer(1);
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ setBuffer(1);
+ setDefaultFrameRateCompatibility(1, ANATIVEWINDOW_FRAME_RATE_MIN);
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ auto summary = summarizeLayerHistory(time);
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneInvisibleLayer) {
+ createLegacyAndFrontedEndLayer(1);
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ setBuffer(1);
+ updateLayerSnapshotsAndLayerHistory(time);
+ auto summary = summarizeLayerHistory(time);
+ ASSERT_EQ(1u, 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(1u, activeLayerCount());
+
+ hideLayer(1);
+ setBuffer(1);
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ summary = summarizeLayerHistory(time);
+ EXPECT_TRUE(summarizeLayerHistory(time).empty());
+ EXPECT_EQ(0u, activeLayerCount());
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitVote) {
+ createLegacyAndFrontedEndLayer(1);
+ setFrameRate(1, 73.4f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(73.4_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitExactVote) {
+ 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);
+ 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));
+}
+
+TEST_F(LayerHistoryIntegrationTest, oneLayerExplicitCategory) {
+ createLegacyAndFrontedEndLayer(1);
+ setFrameRateCategory(1, ANATIVEWINDOW_FRAME_RATE_CATEGORY_HIGH);
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ updateLayerSnapshotsAndLayerHistory(time);
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(1u, 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);
+}
+
+TEST_F(LayerHistoryIntegrationTest, multipleLayers) {
+ auto layer1 = createLegacyAndFrontedEndLayer(1);
+ auto layer2 = createLegacyAndFrontedEndLayer(2);
+ auto layer3 = createLegacyAndFrontedEndLayer(3);
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(3u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ LayerHistory::Summary summary;
+
+ // layer1 is active but infrequent.
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer1, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer2 is frequent and has high refresh rate.
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer2, time);
+ time += HI_FPS_PERIOD;
+ summary = summarizeLayerHistory(time);
+ }
+
+ // layer1 is still active but infrequent.
+ setBufferWithPresentTime(layer1, time);
+
+ ASSERT_EQ(2u, 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(2u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer1 is no longer active.
+ // layer2 is frequent and has low refresh rate.
+ for (size_t i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer2, time);
+ time += LO_FPS_PERIOD;
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(1u, 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 (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ if (i % RATIO == 0) {
+ setBufferWithPresentTime(layer2, time);
+ }
+
+ setBufferWithPresentTime(layer3, time);
+ time += HI_FPS_PERIOD;
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(2u, 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(2u, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer3 becomes recently active.
+ setBufferWithPresentTime(layer3, time);
+ summary = summarizeLayerHistory(time);
+ ASSERT_EQ(2u, 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(2u, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer1 expires.
+ destroyLayer(layer1);
+ updateLayerSnapshotsAndLayerHistory(time);
+
+ summary = summarizeLayerHistory(time);
+ ASSERT_EQ(2u, 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(2u, layerCount());
+ EXPECT_EQ(2u, activeLayerCount());
+ EXPECT_EQ(2, frequentLayerCount(time));
+
+ // layer2 still has low refresh rate.
+ // layer3 becomes inactive.
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ setBufferWithPresentTime(layer2, time);
+ time += LO_FPS_PERIOD;
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer2 expires.
+ destroyLayer(layer2);
+ updateLayerSnapshotsAndLayerHistory(time);
+ summary = summarizeLayerHistory(time);
+ EXPECT_TRUE(summary.empty());
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ // layer3 becomes active and has high refresh rate.
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) {
+ setBufferWithPresentTime(layer3, time);
+ time += HI_FPS_PERIOD;
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_EQ(HI_FPS, summary[0].desiredRefreshRate);
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer3 expires.
+ destroyLayer(layer3);
+ updateLayerSnapshotsAndLayerHistory(time);
+ summary = summarizeLayerHistory(time);
+ EXPECT_TRUE(summary.empty());
+ EXPECT_EQ(0u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, inactiveLayers) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+ nsecs_t time = systemTime();
+
+ // the very first updates makes the layer frequent
+ for (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ EXPECT_EQ(1u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ }
+
+ // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ setBufferWithPresentTime(layer, time);
+
+ EXPECT_EQ(1u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, 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 (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+
+ EXPECT_EQ(1u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ }
+
+ // More quick frames will get us to frequent again
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+
+ EXPECT_EQ(1u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, invisibleExplicitLayer) {
+ auto explicitVisiblelayer = createLegacyAndFrontedEndLayer(1);
+ auto explicitInvisiblelayer = createLegacyAndFrontedEndLayer(2);
+ hideLayer(2);
+ setFrameRate(1, 60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ setFrameRate(2, 90.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+ nsecs_t time = systemTime();
+
+ // Post a buffer to the layers to make them active
+ setBufferWithPresentTime(explicitVisiblelayer, time);
+ setBufferWithPresentTime(explicitInvisiblelayer, 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, infrequentAnimatingLayer) {
+ auto layer = createLegacyAndFrontedEndLayer(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++) {
+ setBufferWithPresentTime(layer, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+ }
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // another update with the same cadence keep in infrequent
+ setBufferWithPresentTime(layer, time);
+ time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ mFlinger.mutableLayerSnapshotBuilder().getSnapshot(1)->changes |=
+ frontend::RequestedLayerState::Changes::Animation;
+ mFlinger.updateLayerHistory(time);
+ // an update as animation will immediately vote for Max
+ 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(1, animatingLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, frequentLayerBecomingInfrequentAndBack) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // Fill up the window with frequent updates
+ for (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += (60_Hz).getPeriodNsecs();
+
+ EXPECT_EQ(1u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ }
+
+ // posting a buffer after long inactivity should retain the layer as active
+ time += std::chrono::nanoseconds(3s).count();
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(0, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1u, 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();
+ setBufferWithPresentTime(layer, time);
+ time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count();
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(0, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // posting another buffer should keep the layer infrequent
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(0, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, 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
+ setBufferWithPresentTime(layer, time);
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(1, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, 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();
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(0, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // posting another buffer should keep the layer frequent
+ time += (60_Hz).getPeriodNsecs();
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(0, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, inconclusiveLayerBecomingFrequent) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+
+ // Fill up the window with frequent updates
+ for (size_t i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) {
+ setBufferWithPresentTime(layer, time);
+ time += (60_Hz).getPeriodNsecs();
+
+ EXPECT_EQ(1u, layerCount());
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, 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();
+ setBufferWithPresentTime(layer, time);
+ time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count();
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(0, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, 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
+ setBufferWithPresentTime(layer, time);
+ setBufferWithPresentTime(layer, time);
+ setBufferWithPresentTime(layer, time);
+ EXPECT_EQ(1, clearLayerHistoryCount(time));
+ ASSERT_EQ(1u, summarizeLayerHistory(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote);
+ EXPECT_EQ(1u, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+ EXPECT_EQ(0, animatingLayerCount(time));
+}
+
+TEST_F(LayerHistoryIntegrationTest, getFramerate) {
+ auto layer = createLegacyAndFrontedEndLayer(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++) {
+ setBufferWithPresentTime(layer, time);
+ 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(LayerHistoryIntegrationTest, heuristicLayer60Hz) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+
+ 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(LayerHistoryIntegrationTest, heuristicLayer60_30Hz) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+
+ 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(LayerHistoryIntegrationTest, heuristicLayerNotOscillating) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+
+ 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(LayerHistoryIntegrationTest, smallDirtyLayer) {
+ auto layer = createLegacyAndFrontedEndLayer(1);
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(1u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ LayerHistory::Summary summary;
+
+ // layer is active but infrequent.
+ for (size_t i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ auto props = layer->getLayerProps();
+ if (i % 3 == 0) {
+ props.isSmallDirty = false;
+ } else {
+ props.isSmallDirty = true;
+ }
+
+ setBufferWithPresentTime(layer, time);
+ time += HI_FPS_PERIOD;
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+ EXPECT_GE(HI_FPS, summary[0].desiredRefreshRate);
+}
+
+TEST_F(LayerHistoryIntegrationTest, DISABLED_smallDirtyInMultiLayer) {
+ auto uiLayer = createLegacyAndFrontedEndLayer(1);
+ auto videoLayer = createLegacyAndFrontedEndLayer(2);
+ setFrameRate(2, 30.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+ ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+
+ nsecs_t time = systemTime();
+
+ EXPECT_EQ(2u, layerCount());
+ EXPECT_EQ(0u, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+
+ LayerHistory::Summary summary;
+
+ // 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;
+ setBuffer(1);
+ uiLayer->setDesiredPresentTime(0, false /*autotimestamp*/);
+ updateLayerSnapshotsAndLayerHistory(time);
+ setBufferWithPresentTime(videoLayer, time);
+ summary = summarizeLayerHistory(time);
+ }
+
+ ASSERT_EQ(1u, summary.size());
+ ASSERT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, summary[0].vote);
+ ASSERT_EQ(30_Hz, summary[0].desiredRefreshRate);
+}
+
+class LayerHistoryIntegrationTestParameterized
+ : public LayerHistoryIntegrationTest,
+ public testing::WithParamInterface<std::chrono::nanoseconds> {};
+
+TEST_P(LayerHistoryIntegrationTestParameterized, HeuristicLayerWithInfrequentLayer) {
+ std::chrono::nanoseconds infrequentUpdateDelta = GetParam();
+ auto heuristicLayer = createLegacyAndFrontedEndLayer(1);
+ auto infrequentLayer = createLegacyAndFrontedEndLayer(2);
+
+ const nsecs_t startTime = systemTime();
+
+ const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns;
+ setBufferWithPresentTime(heuristicLayer, startTime);
+ setBufferWithPresentTime(infrequentLayer, startTime);
+
+ nsecs_t time = startTime;
+ nsecs_t lastInfrequentUpdate = startTime;
+ const size_t totalInfrequentLayerUpdates = FREQUENT_LAYER_WINDOW_SIZE * 5;
+ size_t infrequentLayerUpdates = 0;
+ while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) {
+ time += heuristicUpdateDelta.count();
+ setBufferWithPresentTime(heuristicLayer, time);
+
+ if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) {
+ ALOGI("submitting infrequent frame [%zu/%zu]", infrequentLayerUpdates,
+ totalInfrequentLayerUpdates);
+ lastInfrequentUpdate = time;
+ setBufferWithPresentTime(infrequentLayer, time);
+ infrequentLayerUpdates++;
+ }
+
+ if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) {
+ ASSERT_NE(0u, summarizeLayerHistory(time).size());
+ ASSERT_GE(2u, 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, LayerHistoryIntegrationTestParameterized,
+ ::testing::Values(1s, 2s, 3s, 4s, 5s));
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 549a362..33c1d86 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -45,6 +45,8 @@
using android::mock::createDisplayMode;
+// 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;
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 69316bf..50dfcaa 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -50,27 +50,12 @@
--gtest_filter="LayerSnapshotTest.*" --gtest_brief=1
*/
-class LayerSnapshotTest : public LayerHierarchyTestBase {
+class LayerSnapshotTest : public LayerSnapshotTestBase {
protected:
- LayerSnapshotTest() : LayerHierarchyTestBase() {
+ LayerSnapshotTest() : LayerSnapshotTestBase() {
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
}
- void createRootLayer(uint32_t id) override {
- LayerHierarchyTestBase::createRootLayer(id);
- setColor(id);
- }
-
- void createLayer(uint32_t id, uint32_t parentId) override {
- LayerHierarchyTestBase::createLayer(id, parentId);
- setColor(parentId);
- }
-
- void mirrorLayer(uint32_t id, uint32_t parent, uint32_t layerToMirror) override {
- LayerHierarchyTestBase::mirrorLayer(id, parent, layerToMirror);
- setColor(id);
- }
-
void update(LayerSnapshotBuilder& actualBuilder, LayerSnapshotBuilder::Args& args) {
if (mLifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy)) {
mHierarchyBuilder.update(mLifecycleManager.getLayers(),
@@ -111,11 +96,7 @@
LayerSnapshot* getSnapshot(const LayerHierarchy::TraversalPath path) {
return mSnapshotBuilder.getSnapshot(path);
}
-
- LayerHierarchyBuilder mHierarchyBuilder{{}};
LayerSnapshotBuilder mSnapshotBuilder;
- DisplayInfos mFrontEndDisplayInfos;
- renderengine::ShadowSettings globalShadowSettings;
static const std::vector<uint32_t> STARTING_ZORDER;
};
const std::vector<uint32_t> LayerSnapshotTest::STARTING_ZORDER = {1, 11, 111, 12, 121,
@@ -872,4 +853,12 @@
UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
EXPECT_EQ(getSnapshot(1)->geomContentCrop, Rect(0, 0, 100, 100));
}
+
+TEST_F(LayerSnapshotTest, setShadowRadius) {
+ static constexpr float SHADOW_RADIUS = 123.f;
+ setShadowRadius(1, SHADOW_RADIUS);
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ EXPECT_EQ(getSnapshot(1)->shadowSettings.length, SHADOW_RADIUS);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 173f941..87fae2c 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -192,7 +192,7 @@
// recordLayerHistory should be a noop
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
- mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0,
+ mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, 0,
LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
@@ -218,7 +218,7 @@
kDisplay1Mode60->getId()));
ASSERT_EQ(0u, mScheduler->getNumActiveLayers());
- mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0,
+ mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, 0,
LayerHistory::LayerUpdateType::Buffer);
ASSERT_EQ(1u, mScheduler->getNumActiveLayers());
}
@@ -273,7 +273,7 @@
const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger());
EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true));
- mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0,
+ mScheduler->recordLayerHistory(layer->getSequence(), layer->getLayerProps(), 0, systemTime(),
LayerHistory::LayerUpdateType::Buffer);
constexpr hal::PowerMode kPowerModeOn = hal::PowerMode::ON;
@@ -444,6 +444,63 @@
}
}
+TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) {
+ mScheduler->registerDisplay(kDisplayId1,
+ std::make_shared<RefreshRateSelector>(kDisplay1Modes,
+ kDisplay1Mode60->getId()));
+ mScheduler->registerDisplay(kDisplayId2,
+ std::make_shared<RefreshRateSelector>(kDisplay2Modes,
+ kDisplay2Mode60->getId()));
+
+ using VsyncIds = std::vector<std::pair<PhysicalDisplayId, VsyncId>>;
+
+ struct Compositor final : ICompositor {
+ VsyncIds vsyncIds;
+ bool committed = true;
+
+ void configure() override {}
+
+ bool commit(PhysicalDisplayId, const scheduler::FrameTargets& targets) override {
+ vsyncIds.clear();
+
+ for (const auto& [id, target] : targets) {
+ vsyncIds.emplace_back(id, target->vsyncId());
+ }
+
+ return committed;
+ }
+
+ CompositeResultsPerDisplay composite(PhysicalDisplayId,
+ const scheduler::FrameTargeters&) override {
+ CompositeResultsPerDisplay results;
+
+ for (const auto& [id, _] : vsyncIds) {
+ results.try_emplace(id,
+ CompositeResult{.compositionCoverage =
+ CompositionCoverage::Hwc});
+ }
+
+ return results;
+ }
+
+ void sample() override {}
+ } compositor;
+
+ mScheduler->doFrameSignal(compositor, VsyncId(42));
+
+ const auto makeVsyncIds = [](VsyncId vsyncId) -> VsyncIds {
+ return {{kDisplayId1, vsyncId}, {kDisplayId2, vsyncId}};
+ };
+
+ EXPECT_EQ(makeVsyncIds(VsyncId(42)), compositor.vsyncIds);
+
+ compositor.committed = false;
+ mScheduler->doFrameSignal(compositor, VsyncId(43));
+
+ // FrameTargets should be updated despite the skipped commit.
+ EXPECT_EQ(makeVsyncIds(VsyncId(43)), compositor.vsyncIds);
+}
+
class AttachedChoreographerTest : public SchedulerTest {
protected:
void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps,
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 151b178..014d07c 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -59,6 +59,12 @@
MOCK_METHOD(void, scheduleFrame, (), (override));
MOCK_METHOD(void, postMessage, (sp<MessageHandler>&&), (override));
+ void doFrameSignal(ICompositor& compositor, VsyncId vsyncId) {
+ ftl::FakeGuard guard1(kMainThreadContext);
+ ftl::FakeGuard guard2(mDisplayLock);
+ Scheduler::onFrameSignal(compositor, vsyncId, TimePoint());
+ }
+
// Used to inject mock event thread.
ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
return Scheduler::createConnection(std::move(eventThread));
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index dd998ba..b54392e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -604,6 +604,13 @@
return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get());
}
+ void injectLegacyLayer(sp<Layer> layer) {
+ mFlinger->mLegacyLayers[static_cast<uint32_t>(layer->sequence)] = layer;
+ };
+
+ void releaseLegacyLayer(uint32_t sequence) { mFlinger->mLegacyLayers.erase(sequence); };
+
+ auto updateLayerHistory(nsecs_t now) { return mFlinger->updateLayerHistory(now); };
/* ------------------------------------------------------------------------
* Read-write access to private data to set up preconditions and assert
* post-conditions.
@@ -644,8 +651,8 @@
}
auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
-
auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; }
+ auto& mutableLayerSnapshotBuilder() { return mFlinger->mLayerSnapshotBuilder; };
auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 9b69438..0c48611 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -16,6 +16,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <android/hardware/graphics/common/1.0/types.h>
#include <android/hardware_buffer.h>
@@ -38,6 +39,7 @@
#include "driver.h"
using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
+using DataSpace = aidl::android::hardware::graphics::common::Dataspace;
using android::hardware::graphics::common::V1_0::BufferUsage;
namespace vulkan {
@@ -533,61 +535,51 @@
return native_format;
}
-android_dataspace GetNativeDataspace(VkColorSpaceKHR colorspace,
- PixelFormat pixelFormat) {
+DataSpace GetNativeDataspace(VkColorSpaceKHR colorspace,
+ PixelFormat pixelFormat) {
switch (colorspace) {
case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
- return HAL_DATASPACE_V0_SRGB;
+ return DataSpace::SRGB;
case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:
- return HAL_DATASPACE_DISPLAY_P3;
+ return DataSpace::DISPLAY_P3;
case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
- return HAL_DATASPACE_V0_SCRGB_LINEAR;
+ return DataSpace::SCRGB_LINEAR;
case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
- return HAL_DATASPACE_V0_SCRGB;
+ return DataSpace::SCRGB;
case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
- return HAL_DATASPACE_DCI_P3_LINEAR;
+ return DataSpace::DCI_P3_LINEAR;
case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
- return HAL_DATASPACE_DCI_P3;
+ return DataSpace::DCI_P3;
case VK_COLOR_SPACE_BT709_LINEAR_EXT:
- return HAL_DATASPACE_V0_SRGB_LINEAR;
+ return DataSpace::SRGB_LINEAR;
case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
- return HAL_DATASPACE_V0_SRGB;
+ return DataSpace::SRGB;
case VK_COLOR_SPACE_BT2020_LINEAR_EXT:
if (pixelFormat == PixelFormat::RGBA_FP16) {
- return static_cast<android_dataspace>(
- HAL_DATASPACE_STANDARD_BT2020 |
- HAL_DATASPACE_TRANSFER_LINEAR |
- HAL_DATASPACE_RANGE_EXTENDED);
+ return DataSpace::BT2020_LINEAR_EXTENDED;
} else {
- return HAL_DATASPACE_BT2020_LINEAR;
+ return DataSpace::BT2020_LINEAR;
}
case VK_COLOR_SPACE_HDR10_ST2084_EXT:
- return static_cast<android_dataspace>(
- HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
- HAL_DATASPACE_RANGE_FULL);
+ return DataSpace::BT2020_PQ;
case VK_COLOR_SPACE_DOLBYVISION_EXT:
- return static_cast<android_dataspace>(
- HAL_DATASPACE_STANDARD_BT2020 | HAL_DATASPACE_TRANSFER_ST2084 |
- HAL_DATASPACE_RANGE_FULL);
+ return DataSpace::BT2020_PQ;
case VK_COLOR_SPACE_HDR10_HLG_EXT:
- return static_cast<android_dataspace>(HAL_DATASPACE_BT2020_HLG);
+ return DataSpace::BT2020_HLG;
case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
- return static_cast<android_dataspace>(
- HAL_DATASPACE_STANDARD_ADOBE_RGB |
- HAL_DATASPACE_TRANSFER_LINEAR | HAL_DATASPACE_RANGE_FULL);
+ return DataSpace::ADOBE_RGB_LINEAR;
case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT:
- return HAL_DATASPACE_ADOBE_RGB;
-
+ return DataSpace::ADOBE_RGB;
// Pass through is intended to allow app to provide data that is passed
// to the display system without modification.
case VK_COLOR_SPACE_PASS_THROUGH_EXT:
- return HAL_DATASPACE_ARBITRARY;
+ return DataSpace::ARBITRARY;
default:
// This indicates that we don't know about the
// dataspace specified and we should indicate that
// it's unsupported
- return HAL_DATASPACE_UNKNOWN;
+ return DataSpace::UNKNOWN;
}
}
@@ -1575,9 +1567,9 @@
PixelFormat native_pixel_format =
GetNativePixelFormat(create_info->imageFormat);
- android_dataspace native_dataspace =
+ DataSpace native_dataspace =
GetNativeDataspace(create_info->imageColorSpace, native_pixel_format);
- if (native_dataspace == HAL_DATASPACE_UNKNOWN) {
+ if (native_dataspace == DataSpace::UNKNOWN) {
ALOGE(
"CreateSwapchainKHR(VkSwapchainCreateInfoKHR.imageColorSpace = %d) "
"failed: Unsupported color space",
@@ -1683,8 +1675,9 @@
}
/* Respect consumer default dataspace upon HAL_DATASPACE_ARBITRARY. */
- if (native_dataspace != HAL_DATASPACE_ARBITRARY) {
- err = native_window_set_buffers_data_space(window, native_dataspace);
+ if (native_dataspace != DataSpace::ARBITRARY) {
+ err = native_window_set_buffers_data_space(
+ window, static_cast<android_dataspace_t>(native_dataspace));
if (err != android::OK) {
ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
native_dataspace, strerror(-err), err);