Merge "SF: enable VSyncReactor"
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index d398559..3a3df08 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <ui/DisplayInfo.h>
-#include <gui/SurfaceComposerClient.h>
-
#include "GLHelper.h"
- namespace android {
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+
+namespace android {
GLHelper::GLHelper() :
mDisplay(EGL_NO_DISPLAY),
@@ -228,15 +227,15 @@
return false;
}
- DisplayInfo info;
- status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info);
+ DisplayConfig config;
+ status_t err = mSurfaceComposerClient->getActiveDisplayConfig(dpy, &config);
if (err != NO_ERROR) {
- fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err);
+ fprintf(stderr, "SurfaceComposer::getActiveDisplayConfig failed: %#x\n", err);
return false;
}
- float scaleX = float(info.w) / float(w);
- float scaleY = float(info.h) / float(h);
+ float scaleX = static_cast<float>(config.resolution.getWidth()) / w;
+ float scaleY = static_cast<float>(config.resolution.getHeight()) / h;
*scale = scaleX < scaleY ? scaleX : scaleY;
return true;
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index e7b0d5d..cfd6a3e 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -2250,26 +2250,6 @@
return *_aidl_return ? ok() : error("viewcompiler failed");
}
-binder::Status InstalldNativeService::markBootComplete(const std::string& instructionSet) {
- ENFORCE_UID(AID_SYSTEM);
- std::lock_guard<std::recursive_mutex> lock(mLock);
-
- const char* instruction_set = instructionSet.c_str();
-
- char boot_marker_path[PKG_PATH_MAX];
- sprintf(boot_marker_path,
- "%s/%s/%s/.booting",
- android_data_dir.c_str(),
- DALVIK_CACHE,
- instruction_set);
-
- ALOGV("mark_boot_complete : %s", boot_marker_path);
- if (unlink(boot_marker_path) != 0) {
- return error(StringPrintf("Failed to unlink %s", boot_marker_path));
- }
- return ok();
-}
-
binder::Status InstalldNativeService::linkNativeLibraryDirectory(
const std::unique_ptr<std::string>& uuid, const std::string& packageName,
const std::string& nativeLibPath32, int32_t userId) {
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index bf11002..dd56de6 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -130,7 +130,6 @@
const std::string& profileName);
binder::Status rmPackageDir(const std::string& packageDir);
- binder::Status markBootComplete(const std::string& instructionSet);
binder::Status freeCache(const std::unique_ptr<std::string>& uuid, int64_t targetFreeBytes,
int64_t cacheReservedBytes, int32_t flags);
binder::Status linkNativeLibraryDirectory(const std::unique_ptr<std::string>& uuid,
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 891b26d..07ced0d 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -81,7 +81,6 @@
void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String profileName);
void rmPackageDir(@utf8InCpp String packageDir);
- void markBootComplete(@utf8InCpp String instructionSet);
void freeCache(@nullable @utf8InCpp String uuid, long targetFreeBytes,
long cacheReservedBytes, int flags);
void linkNativeLibraryDirectory(@nullable @utf8InCpp String uuid,
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index ae74ac3..abe6436 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -423,11 +423,12 @@
void ServiceManager::handleClientCallbacks() {
for (const auto& [name, service] : mNameToService) {
- handleServiceClientCallback(name);
+ handleServiceClientCallback(name, true);
}
}
-ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName) {
+ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName,
+ bool isCalledOnInterval) {
auto serviceIt = mNameToService.find(serviceName);
if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) {
return -1;
@@ -451,14 +452,17 @@
service.guaranteeClient = false;
}
- if (hasClients && !service.hasClients) {
- // client was retrieved in some other way
- sendClientCallbackNotifications(serviceName, true);
- }
+ // only send notifications if this was called via the interval checking workflow
+ if (isCalledOnInterval) {
+ if (hasClients && !service.hasClients) {
+ // client was retrieved in some other way
+ sendClientCallbackNotifications(serviceName, true);
+ }
- // there are no more clients, but the callback has not been called yet
- if (!hasClients && service.hasClients) {
- sendClientCallbackNotifications(serviceName, false);
+ // there are no more clients, but the callback has not been called yet
+ if (!hasClients && service.hasClients) {
+ sendClientCallbackNotifications(serviceName, false);
+ }
}
return count;
@@ -518,7 +522,7 @@
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
- int clients = handleServiceClientCallback(name);
+ int clients = handleServiceClientCallback(name, false);
// clients < 0: feature not implemented or other error. Assume clients.
// Otherwise:
@@ -527,7 +531,7 @@
// So, if clients > 2, then at least one other service on the system must hold a refcount.
if (clients < 0 || clients > 2) {
// client callbacks are either disabled or there are other clients
- LOG(INFO) << "Tried to unregister " << name << " but there are clients: " << clients;
+ LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients;
return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
}
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index 77f5250..a2fc5a8 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -75,7 +75,7 @@
void removeRegistrationCallback(const wp<IBinder>& who,
ServiceCallbackMap::iterator* it,
bool* found);
- ssize_t handleServiceClientCallback(const std::string& serviceName);
+ ssize_t handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval);
// Also updates mHasClients (of what the last callback was)
void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients);
// removes a callback from mNameToClientCallback, deleting the entry if the vector is empty
diff --git a/include/input/Input.h b/include/input/Input.h
index 1cf58ef..cf0814c 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -354,9 +354,9 @@
inline int32_t getDeviceId() const { return mDeviceId; }
- inline int32_t getSource() const { return mSource; }
+ inline uint32_t getSource() const { return mSource; }
- inline void setSource(int32_t source) { mSource = source; }
+ inline void setSource(uint32_t source) { mSource = source; }
inline int32_t getDisplayId() const { return mDisplayId; }
@@ -365,12 +365,12 @@
inline std::array<uint8_t, 32> getHmac() const { return mHmac; }
protected:
- void initialize(int32_t deviceId, int32_t source, int32_t displayId,
+ void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac);
void initialize(const InputEvent& from);
int32_t mDeviceId;
- int32_t mSource;
+ uint32_t mSource;
int32_t mDisplayId;
std::array<uint8_t, 32> mHmac;
};
@@ -405,7 +405,7 @@
static const char* getLabel(int32_t keyCode);
static int32_t getKeyCodeFromLabel(const char* label);
- void initialize(int32_t deviceId, int32_t source, int32_t displayId,
+ void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t flags, int32_t keyCode,
int32_t scanCode, int32_t metaState, int32_t repeatCount, nsecs_t downTime,
nsecs_t eventTime);
@@ -629,7 +629,7 @@
ssize_t findPointerIndex(int32_t pointerId) const;
- void initialize(int32_t deviceId, int32_t source, int32_t displayId,
+ void initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
MotionClassification classification, float xScale, float yScale, float xOffset,
@@ -657,7 +657,7 @@
status_t writeToParcel(Parcel* parcel) const;
#endif
- static bool isTouchEvent(int32_t source, int32_t action);
+ static bool isTouchEvent(uint32_t source, int32_t action);
inline bool isTouchEvent() const {
return isTouchEvent(mSource, mAction);
}
diff --git a/libs/adbd_auth/Android.bp b/libs/adbd_auth/Android.bp
index 9cf0143..8ac044c 100644
--- a/libs/adbd_auth/Android.bp
+++ b/libs/adbd_auth/Android.bp
@@ -20,11 +20,14 @@
"-Wthread-safety",
"-Werror",
],
+ stl: "libc++_static",
+
srcs: ["adbd_auth.cpp"],
export_include_dirs: ["include"],
version_script: "libadbd_auth.map.txt",
stubs: {
+ versions: ["1"],
symbol_file: "libadbd_auth.map.txt",
},
@@ -36,7 +39,7 @@
}
},
- shared_libs: [
+ static_libs: [
"libbase",
"libcutils",
"liblog",
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 079dd82..1ee3853 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -73,7 +73,6 @@
// or dessert updates. Instead, apex users should use libbinder_ndk.
apex_available: [
"//apex_available:platform",
- "com.android.vndk.current",
// TODO(b/139016109) remove these three
"com.android.media.swcodec",
"test_com.android.media.swcodec",
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 238c9dc..f16c39c 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -435,7 +435,8 @@
Vector<Obituary>* obits = mObituaries;
if(obits != nullptr) {
if (!obits->isEmpty()) {
- ALOGI("onLastStrongRef automatically unlinking death recipients");
+ ALOGI("onLastStrongRef automatically unlinking death recipients: %s",
+ mDescriptorCache.size() ? String8(mDescriptorCache).c_str() : "<uncached descriptor>");
}
if (ipc) ipc->clearDeathNotification(mHandle, this);
diff --git a/libs/binder/BufferedTextOutput.cpp b/libs/binder/BufferedTextOutput.cpp
index 824b56b..8cf6097 100644
--- a/libs/binder/BufferedTextOutput.cpp
+++ b/libs/binder/BufferedTextOutput.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <binder/BufferedTextOutput.h>
+#include "BufferedTextOutput.h"
#include <binder/Debug.h>
#include <cutils/atomic.h>
diff --git a/libs/binder/include/binder/BufferedTextOutput.h b/libs/binder/BufferedTextOutput.h
similarity index 100%
rename from libs/binder/include/binder/BufferedTextOutput.h
rename to libs/binder/BufferedTextOutput.h
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 5ca9156..328653a 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -85,10 +85,11 @@
sp<AidlServiceManager> mTheRealServiceManager;
};
+static Mutex gDefaultServiceManagerLock;
+static sp<IServiceManager> gDefaultServiceManager;
+
sp<IServiceManager> defaultServiceManager()
{
- static Mutex gDefaultServiceManagerLock;
- static sp<IServiceManager> gDefaultServiceManager;
if (gDefaultServiceManager != nullptr) return gDefaultServiceManager;
@@ -106,6 +107,11 @@
return gDefaultServiceManager;
}
+void setDefaultServiceManager(const sp<IServiceManager>& sm) {
+ AutoMutex _l(gDefaultServiceManagerLock);
+ gDefaultServiceManager = sm;
+}
+
#if !defined(__ANDROID_VNDK__) && defined(__ANDROID__)
// IPermissionController is not accessible to vendors
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index dc9482c..f064bd7 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -53,14 +53,13 @@
struct Service {
sp<IBinder> service;
- std::string name;
bool allowIsolated;
int dumpFlags;
};
/**
- * Number of services that have been registered.
+ * Map of registered names and services
*/
- std::vector<Service> mRegisteredServices;
+ std::map<std::string, Service> mRegisteredServices;
};
bool ClientCounterCallback::registerService(const sp<IBinder>& service, const std::string& name,
@@ -68,20 +67,24 @@
auto manager = interface_cast<AidlServiceManager>(
ProcessState::self()->getContextObject(nullptr));
- ALOGI("Registering service %s", name.c_str());
+ bool reRegister = mRegisteredServices.count(name) > 0;
+ std::string regStr = (reRegister) ? "Re-registering" : "Registering";
+ ALOGI("%s service %s", regStr.c_str(), name.c_str());
if (!manager->addService(name.c_str(), service, allowIsolated, dumpFlags).isOk()) {
ALOGE("Failed to register service %s", name.c_str());
return false;
}
- if (!manager->registerClientCallback(name, service, this).isOk())
- {
- ALOGE("Failed to add client callback for service %s", name.c_str());
- return false;
+ if (!manager->registerClientCallback(name, service, this).isOk()) {
+ ALOGE("Failed to add client callback for service %s", name.c_str());
+ return false;
}
- mRegisteredServices.push_back({service, name, allowIsolated, dumpFlags});
+ if (!reRegister) {
+ // Only add this when a service is added for the first time, as it is not removed
+ mRegisteredServices[name] = {service, allowIsolated, dumpFlags};
+ }
return true;
}
@@ -119,10 +122,11 @@
for (; unRegisterIt != mRegisteredServices.end(); ++unRegisterIt) {
auto& entry = (*unRegisterIt);
- bool success = manager->tryUnregisterService(entry.name, entry.service).isOk();
+ bool success = manager->tryUnregisterService(entry.first, entry.second.service).isOk();
+
if (!success) {
- ALOGI("Failed to unregister service %s", entry.name.c_str());
+ ALOGI("Failed to unregister service %s", entry.first.c_str());
break;
}
}
@@ -137,7 +141,8 @@
auto& entry = (*reRegisterIt);
// re-register entry
- if (!registerService(entry.service, entry.name, entry.allowIsolated, entry.dumpFlags)) {
+ if (!registerService(entry.second.service, entry.first, entry.second.allowIsolated,
+ entry.second.dumpFlags)) {
// Must restart. Otherwise, clients will never be able to get a hold of this service.
ALOGE("Bad state: could not re-register services");
}
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 994e3b9..9f8d752 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -507,7 +507,7 @@
}
}
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
constexpr int32_t kHeader = B_PACK_CHARS('V', 'N', 'D', 'R');
#else
constexpr int32_t kHeader = B_PACK_CHARS('S', 'Y', 'S', 'T');
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 37c0d77..bdc2e40 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -60,14 +60,14 @@
: mIsMain(isMain)
{
}
-
+
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
-
+
const bool mIsMain;
};
@@ -296,7 +296,7 @@
void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
{
AutoMutex _l(mLock);
-
+
handle_entry* e = lookupHandleLocked(handle);
// This handle may have already been replaced with a new BpBinder
@@ -387,7 +387,7 @@
{
// TODO(b/139016109): enforce in build system
-#if defined(__ANDROID_APEX__) && !defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__)
+#if defined(__ANDROID_APEX__)
LOG_ALWAYS_FATAL("Cannot use libbinder in APEX (only system.img libbinder) since it is not stable.");
#endif
@@ -418,5 +418,5 @@
}
mDriverFD = -1;
}
-
+
} // namespace android
diff --git a/libs/binder/Static.cpp b/libs/binder/Static.cpp
index bd40536..7a77f6d 100644
--- a/libs/binder/Static.cpp
+++ b/libs/binder/Static.cpp
@@ -19,7 +19,7 @@
#include "Static.h"
-#include <binder/BufferedTextOutput.h>
+#include "BufferedTextOutput.h"
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 55419eb..7489afa 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -23,6 +23,9 @@
},
{
"name": "CtsNdkBinderTestCases"
+ },
+ {
+ "name": "aidl_lazy_test"
}
]
}
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 2c43263..31f022d 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -100,6 +100,11 @@
sp<IServiceManager> defaultServiceManager();
+/**
+ * Directly set the default service manager. Only used for testing.
+ */
+void setDefaultServiceManager(const sp<IServiceManager>& sm);
+
template<typename INTERFACE>
sp<INTERFACE> waitForService(const String16& name) {
const sp<IServiceManager> sm = defaultServiceManager();
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
index b2f51d3..2894482 100644
--- a/libs/binder/include/binder/Stability.h
+++ b/libs/binder/include/binder/Stability.h
@@ -81,7 +81,7 @@
VINTF = 0b111111,
};
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
static constexpr Level kLocalStability = Level::VENDOR;
#else
static constexpr Level kLocalStability = Level::SYSTEM;
diff --git a/libs/binder/ndk/include_platform/android/binder_stability.h b/libs/binder/ndk/include_platform/android/binder_stability.h
index 56d95a7..f5e8bf6 100644
--- a/libs/binder/ndk/include_platform/android/binder_stability.h
+++ b/libs/binder/ndk/include_platform/android/binder_stability.h
@@ -30,8 +30,7 @@
FLAG_PRIVATE_VENDOR = 0x10000000,
};
-#if defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || \
- (defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__))
+#if defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
enum {
FLAG_PRIVATE_LOCAL = FLAG_PRIVATE_VENDOR,
@@ -46,8 +45,7 @@
AIBinder_markVendorStability(binder);
}
-#else // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
- // !defined(__ANDROID_APEX__))
+#else // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
enum {
FLAG_PRIVATE_LOCAL = 0,
@@ -64,8 +62,7 @@
AIBinder_markSystemStability(binder);
}
-#endif // defined(__ANDROID_APEX_COM_ANDROID_VNDK_CURRENT__) || (defined(__ANDROID_VNDK__) &&
- // !defined(__ANDROID_APEX__))
+#endif // defined(__ANDROID_VNDK__) && !defined(__ANDROID_APEX__)
/**
* This interface has system<->vendor stability
diff --git a/libs/binder/ndk/test/Android.bp b/libs/binder/ndk/test/Android.bp
index e598eec..513d8c2 100644
--- a/libs/binder/ndk/test/Android.bp
+++ b/libs/binder/ndk/test/Android.bp
@@ -59,6 +59,9 @@
name: "libbinder_ndk_unit_test",
defaults: ["test_libbinder_ndk_test_defaults"],
srcs: ["libbinder_ndk_unit_test.cpp"],
+ static_libs: [
+ "IBinderNdkUnitTest-ndk_platform",
+ ],
test_suites: ["general-tests"],
require_root: true,
@@ -93,3 +96,11 @@
"IBinderVendorDoubleLoadTest.aidl",
],
}
+
+aidl_interface {
+ name: "IBinderNdkUnitTest",
+ srcs: [
+ "IBinderNdkUnitTest.aidl",
+ "IEmpty.aidl",
+ ],
+}
diff --git a/libs/binder/ndk/test/IBinderNdkUnitTest.aidl b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
new file mode 100644
index 0000000..6e8e463
--- /dev/null
+++ b/libs/binder/ndk/test/IBinderNdkUnitTest.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// This AIDL is to test things that can't be tested in CtsNdkBinderTestCases
+// because it requires libbinder_ndk implementation details or APIs not
+// available to apps. Please prefer adding tests to CtsNdkBinderTestCases
+// over here.
+
+import IEmpty;
+
+interface IBinderNdkUnitTest {
+ void takeInterface(IEmpty test);
+ void forceFlushCommands();
+}
diff --git a/libs/binder/ndk/test/IEmpty.aidl b/libs/binder/ndk/test/IEmpty.aidl
new file mode 100644
index 0000000..95e4341
--- /dev/null
+++ b/libs/binder/ndk/test/IEmpty.aidl
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+interface IEmpty { }
diff --git a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
index 8aba411..51dd169 100644
--- a/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
+++ b/libs/binder/ndk/test/libbinder_ndk_unit_test.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <aidl/BnBinderNdkUnitTest.h>
+#include <aidl/BnEmpty.h>
#include <android-base/logging.h>
#include <android/binder_ibinder_jni.h>
#include <android/binder_manager.h>
@@ -21,6 +23,10 @@
#include <gtest/gtest.h>
#include <iface/iface.h>
+// warning: this is assuming that libbinder_ndk is using the same copy
+// of libbinder that we are.
+#include <binder/IPCThreadState.h>
+
#include <sys/prctl.h>
#include <chrono>
#include <condition_variable>
@@ -29,7 +35,38 @@
using ::android::sp;
constexpr char kExistingNonNdkService[] = "SurfaceFlinger";
+constexpr char kBinderNdkUnitTestService[] = "BinderNdkUnitTest";
+class MyBinderNdkUnitTest : public aidl::BnBinderNdkUnitTest {
+ ndk::ScopedAStatus takeInterface(const std::shared_ptr<aidl::IEmpty>& empty) {
+ (void)empty;
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus forceFlushCommands() {
+ // warning: this is assuming that libbinder_ndk is using the same copy
+ // of libbinder that we are.
+ android::IPCThreadState::self()->flushCommands();
+ return ndk::ScopedAStatus::ok();
+ }
+};
+
+int generatedService() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ auto service = ndk::SharedRefBase::make<MyBinderNdkUnitTest>();
+ binder_status_t status =
+ AServiceManager_addService(service->asBinder().get(), kBinderNdkUnitTestService);
+
+ if (status != STATUS_OK) {
+ LOG(FATAL) << "Could not register: " << status << " " << kBinderNdkUnitTestService;
+ }
+
+ ABinderProcess_joinThreadPool();
+
+ return 1; // should not return
+}
+
+// manually-written parceling class considered bad practice
class MyFoo : public IFoo {
binder_status_t doubleNumber(int32_t in, int32_t* out) override {
*out = 2 * in;
@@ -43,7 +80,7 @@
}
};
-int service(const char* instance) {
+int manualService(const char* instance) {
ABinderProcess_setThreadPoolMaxThreadCount(0);
// Strong reference to MyFoo kept by service manager.
@@ -225,16 +262,54 @@
EXPECT_EQ(IFoo::getService(kInstanceName1), IFoo::getService(kInstanceName2));
}
+TEST(NdkBinder, SentAidlBinderCanBeDestroyed) {
+ static volatile bool destroyed = false;
+ static std::mutex dMutex;
+ static std::condition_variable cv;
+
+ class MyEmpty : public aidl::BnEmpty {
+ virtual ~MyEmpty() {
+ destroyed = true;
+ cv.notify_one();
+ }
+ };
+
+ std::shared_ptr<MyEmpty> empty = ndk::SharedRefBase::make<MyEmpty>();
+
+ ndk::SpAIBinder binder(AServiceManager_getService(kBinderNdkUnitTestService));
+ std::shared_ptr<aidl::IBinderNdkUnitTest> service =
+ aidl::IBinderNdkUnitTest::fromBinder(binder);
+
+ EXPECT_FALSE(destroyed);
+
+ service->takeInterface(empty);
+ service->forceFlushCommands();
+ empty = nullptr;
+
+ // give other binder thread time to process commands
+ {
+ using namespace std::chrono_literals;
+ std::unique_lock<std::mutex> lk(dMutex);
+ cv.wait_for(lk, 1s, [] { return destroyed; });
+ }
+
+ EXPECT_TRUE(destroyed);
+}
+
int main(int argc, char* argv[]) {
::testing::InitGoogleTest(&argc, argv);
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return service(IFoo::kInstanceNameToDieFor);
+ return manualService(IFoo::kInstanceNameToDieFor);
}
if (fork() == 0) {
prctl(PR_SET_PDEATHSIG, SIGHUP);
- return service(IFoo::kSomeInstanceName);
+ return manualService(IFoo::kSomeInstanceName);
+ }
+ if (fork() == 0) {
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+ return generatedService();
}
ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications/callbacks
diff --git a/libs/fakeservicemanager/Android.bp b/libs/fakeservicemanager/Android.bp
new file mode 100644
index 0000000..de32ff4
--- /dev/null
+++ b/libs/fakeservicemanager/Android.bp
@@ -0,0 +1,25 @@
+cc_defaults {
+ name: "fakeservicemanager_defaults",
+ srcs: [
+ "ServiceManager.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+}
+
+cc_library {
+ name: "libfakeservicemanager",
+ defaults: ["fakeservicemanager_defaults"],
+}
+
+cc_test_host {
+ name: "fakeservicemanager_test",
+ defaults: ["fakeservicemanager_defaults"],
+ srcs: [
+ "test_sm.cpp",
+ ],
+ static_libs: ["libgmock"],
+}
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
new file mode 100644
index 0000000..6964324
--- /dev/null
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ServiceManager.h"
+
+namespace android {
+
+ServiceManager::ServiceManager() {}
+
+sp<IBinder> ServiceManager::getService( const String16& name) const {
+ // Servicemanager is single-threaded and cannot block. This method exists for legacy reasons.
+ return checkService(name);
+}
+
+sp<IBinder> ServiceManager::checkService( const String16& name) const {
+ auto it = mNameToService.find(name);
+ if (it == mNameToService.end()) {
+ return nullptr;
+ }
+ return it->second;
+}
+
+status_t ServiceManager::addService(const String16& name, const sp<IBinder>& service,
+ bool /*allowIsolated*/,
+ int /*dumpsysFlags*/) {
+ mNameToService[name] = service;
+ return NO_ERROR;
+}
+
+Vector<String16> ServiceManager::listServices(int /*dumpsysFlags*/) {
+ Vector<String16> services;
+ for (auto const& [name, service] : mNameToService) {
+ (void) service;
+ services.push_back(name);
+ }
+ return services;
+}
+
+IBinder* ServiceManager::onAsBinder() {
+ return nullptr;
+}
+
+sp<IBinder> ServiceManager::waitForService(const String16& name) {
+ return checkService(name);
+}
+
+bool ServiceManager::isDeclared(const String16& name) {
+ return mNameToService.find(name) != mNameToService.end();
+}
+
+} // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
new file mode 100644
index 0000000..62311d4
--- /dev/null
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IServiceManager.h>
+
+#include <map>
+
+namespace android {
+
+/**
+ * A local host simple implementation of IServiceManager, that does not
+ * communicate over binder.
+*/
+class ServiceManager : public IServiceManager {
+public:
+ ServiceManager();
+
+ /**
+ * Equivalent of checkService.
+ */
+ sp<IBinder> getService( const String16& name) const override;
+
+ /**
+ * Retrieve an existing service, non-blocking.
+ */
+ sp<IBinder> checkService( const String16& name) const override;
+
+ /**
+ * Register a service.
+ */
+ status_t addService(const String16& name, const sp<IBinder>& service,
+ bool allowIsolated = false,
+ int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) override;
+
+ /**
+ * Return list of all existing services.
+ */
+ Vector<String16> listServices(int dumpsysFlags = 0) override;
+
+ IBinder* onAsBinder() override;
+
+ /**
+ * Effectively no-oped in this implementation - equivalent to checkService.
+ */
+ sp<IBinder> waitForService(const String16& name) override;
+
+ /**
+ * Check if a service is declared (e.g. VINTF manifest).
+ *
+ * If this returns true, waitForService should always be able to return the
+ * service.
+ */
+ bool isDeclared(const String16& name) override;
+
+private:
+ std::map<String16, sp<IBinder>> mNameToService;
+};
+
+} // namespace android
diff --git a/libs/fakeservicemanager/test_sm.cpp b/libs/fakeservicemanager/test_sm.cpp
new file mode 100644
index 0000000..71e5abe
--- /dev/null
+++ b/libs/fakeservicemanager/test_sm.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include <binder/Binder.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+
+#include "ServiceManager.h"
+
+using android::sp;
+using android::BBinder;
+using android::IBinder;
+using android::OK;
+using android::status_t;
+using android::ServiceManager;
+using android::String16;
+using android::IServiceManager;
+using testing::ElementsAre;
+
+static sp<IBinder> getBinder() {
+ class LinkableBinder : public BBinder {
+ status_t linkToDeath(const sp<DeathRecipient>&, void*, uint32_t) override {
+ // let SM linkToDeath
+ return OK;
+ }
+ };
+
+ return new LinkableBinder;
+}
+
+TEST(AddService, HappyHappy) {
+ auto sm = new ServiceManager();
+ EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+}
+
+TEST(AddService, HappyOverExistingService) {
+ auto sm = new ServiceManager();
+ EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+ EXPECT_EQ(sm->addService(String16("foo"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+}
+
+TEST(GetService, HappyHappy) {
+ auto sm = new ServiceManager();
+ sp<IBinder> service = getBinder();
+
+ EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ EXPECT_EQ(sm->getService(String16("foo")), service);
+}
+
+TEST(GetService, NonExistant) {
+ auto sm = new ServiceManager();
+
+ EXPECT_EQ(sm->getService(String16("foo")), nullptr);
+}
+
+TEST(ListServices, AllServices) {
+ auto sm = new ServiceManager();
+
+ EXPECT_EQ(sm->addService(String16("sd"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+ EXPECT_EQ(sm->addService(String16("sc"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_NORMAL), OK);
+ EXPECT_EQ(sm->addService(String16("sb"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_HIGH), OK);
+ EXPECT_EQ(sm->addService(String16("sa"), getBinder(), false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL), OK);
+
+ android::Vector<String16> out = sm->listServices(IServiceManager::DUMP_FLAG_PRIORITY_ALL);
+
+ // all there and in the right order
+ EXPECT_THAT(out, ElementsAre(String16("sa"), String16("sb"), String16("sc"),
+ String16("sd")));
+}
+
+TEST(WaitForService, NonExistant) {
+ auto sm = new ServiceManager();
+
+ EXPECT_EQ(sm->waitForService(String16("foo")), nullptr);
+}
+
+TEST(WaitForService, HappyHappy) {
+ auto sm = new ServiceManager();
+ sp<IBinder> service = getBinder();
+
+ EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ EXPECT_EQ(sm->waitForService(String16("foo")), service);
+}
+
+TEST(IsDeclared, NonExistant) {
+ auto sm = new ServiceManager();
+
+ EXPECT_FALSE(sm->isDeclared(String16("foo")));
+}
+
+TEST(IsDeclared, HappyHappy) {
+ auto sm = new ServiceManager();
+ sp<IBinder> service = getBinder();
+
+ EXPECT_EQ(sm->addService(String16("foo"), service, false /*allowIsolated*/,
+ IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT), OK);
+
+ EXPECT_TRUE(sm->isDeclared(String16("foo")));
+}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 3f359f5..4e62da7 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -83,6 +83,7 @@
if (stats.size() > 0) {
mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
mTransformHint = stats[0].transformHint;
+ mBufferItemConsumer->setTransformHint(mTransformHint);
} else {
ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
mPendingReleaseItem.releaseFence = nullptr;
@@ -151,7 +152,7 @@
bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
- t->setFrame(mSurfaceControl, {0, 0, (int32_t)buffer->getWidth(), (int32_t)buffer->getHeight()});
+ t->setFrame(mSurfaceControl, {0, 0, mWidth, mHeight});
t->setCrop(mSurfaceControl, computeCrop(bufferItem));
t->setTransform(mSurfaceControl, bufferItem.mTransform);
t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 3b0120b..9e5d681 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -84,54 +84,54 @@
return INVALID_OPERATION;
}
-BufferQueueCore::BufferQueueCore() :
- mMutex(),
- mIsAbandoned(false),
- mConsumerControlledByApp(false),
- mConsumerName(getUniqueName()),
- mConsumerListener(),
- mConsumerUsageBits(0),
- mConsumerIsProtected(false),
- mConnectedApi(NO_CONNECTED_API),
- mLinkedToDeath(),
- mConnectedProducerListener(),
- mBufferReleasedCbEnabled(false),
- mSlots(),
- mQueue(),
- mFreeSlots(),
- mFreeBuffers(),
- mUnusedSlots(),
- mActiveBuffers(),
- mDequeueCondition(),
- mDequeueBufferCannotBlock(false),
- mQueueBufferCanDrop(false),
- mLegacyBufferDrop(true),
- mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
- mDefaultWidth(1),
- mDefaultHeight(1),
- mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
- mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
- mMaxAcquiredBufferCount(1),
- mMaxDequeuedBufferCount(1),
- mBufferHasBeenQueued(false),
- mFrameCounter(0),
- mTransformHint(0),
- mIsAllocating(false),
- mIsAllocatingCondition(),
- mAllowAllocation(true),
- mBufferAge(0),
- mGenerationNumber(0),
- mAsyncMode(false),
- mSharedBufferMode(false),
- mAutoRefresh(false),
- mSharedBufferSlot(INVALID_BUFFER_SLOT),
- mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
- HAL_DATASPACE_UNKNOWN),
- mLastQueuedSlot(INVALID_BUFFER_SLOT),
- mUniqueId(getUniqueId()),
- mAutoPrerotation(false),
- mTransformHintInUse(0)
-{
+BufferQueueCore::BufferQueueCore()
+ : mMutex(),
+ mIsAbandoned(false),
+ mConsumerControlledByApp(false),
+ mConsumerName(getUniqueName()),
+ mConsumerListener(),
+ mConsumerUsageBits(0),
+ mConsumerIsProtected(false),
+ mConnectedApi(NO_CONNECTED_API),
+ mLinkedToDeath(),
+ mConnectedProducerListener(),
+ mBufferReleasedCbEnabled(false),
+ mSlots(),
+ mQueue(),
+ mFreeSlots(),
+ mFreeBuffers(),
+ mUnusedSlots(),
+ mActiveBuffers(),
+ mDequeueCondition(),
+ mDequeueBufferCannotBlock(false),
+ mQueueBufferCanDrop(false),
+ mLegacyBufferDrop(true),
+ mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
+ mDefaultWidth(1),
+ mDefaultHeight(1),
+ mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
+ mMaxBufferCount(BufferQueueDefs::NUM_BUFFER_SLOTS),
+ mMaxAcquiredBufferCount(1),
+ mMaxDequeuedBufferCount(1),
+ mBufferHasBeenQueued(false),
+ mFrameCounter(0),
+ mTransformHint(0),
+ mIsAllocating(false),
+ mIsAllocatingCondition(),
+ mAllowAllocation(true),
+ mBufferAge(0),
+ mGenerationNumber(0),
+ mAsyncMode(false),
+ mSharedBufferMode(false),
+ mAutoRefresh(false),
+ mSharedBufferSlot(INVALID_BUFFER_SLOT),
+ mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
+ HAL_DATASPACE_UNKNOWN),
+ mLastQueuedSlot(INVALID_BUFFER_SLOT),
+ mUniqueId(getUniqueId()),
+ mAutoPrerotation(false),
+ mTransformHintInUse(0),
+ mFrameRate(0) {
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
mFreeSlots.insert(s);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 073543c..2f27fd2 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -34,8 +34,10 @@
#include <system/graphics.h>
+#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/DisplayState.h>
#include <ui/HdrCapabilities.h>
#include <utils/Log.h>
@@ -351,22 +353,43 @@
remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply);
}
- virtual status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs)
- {
+ virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState* state) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ remote()->transact(BnSurfaceComposer::GET_DISPLAY_STATE, data, &reply);
+ const status_t result = reply.readInt32();
+ if (result == NO_ERROR) {
+ memcpy(state, reply.readInplace(sizeof(ui::DisplayState)), sizeof(ui::DisplayState));
+ }
+ return result;
+ }
+
+ virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
+ Parcel data, reply;
+ data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+ data.writeStrongBinder(display);
+ remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply);
+ const status_t result = reply.readInt32();
+ if (result == NO_ERROR) {
+ memcpy(info, reply.readInplace(sizeof(DisplayInfo)), sizeof(DisplayInfo));
+ }
+ return result;
+ }
+
+ virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>* configs) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
data.writeStrongBinder(display);
remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply);
- status_t result = reply.readInt32();
+ const status_t result = reply.readInt32();
if (result == NO_ERROR) {
- size_t numConfigs = reply.readUint32();
+ const size_t numConfigs = reply.readUint32();
configs->clear();
configs->resize(numConfigs);
for (size_t c = 0; c < numConfigs; ++c) {
- memcpy(&(configs->editItemAt(c)),
- reply.readInplace(sizeof(DisplayInfo)),
- sizeof(DisplayInfo));
+ memcpy(&(configs->editItemAt(c)), reply.readInplace(sizeof(DisplayConfig)),
+ sizeof(DisplayConfig));
}
}
return result;
@@ -1297,17 +1320,40 @@
reply->writeStrongBinder(display);
return NO_ERROR;
}
+ case GET_DISPLAY_STATE: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ ui::DisplayState state;
+ const sp<IBinder> display = data.readStrongBinder();
+ const status_t result = getDisplayState(display, &state);
+ reply->writeInt32(result);
+ if (result == NO_ERROR) {
+ memcpy(reply->writeInplace(sizeof(ui::DisplayState)), &state,
+ sizeof(ui::DisplayState));
+ }
+ return NO_ERROR;
+ }
+ case GET_DISPLAY_INFO: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ DisplayInfo info;
+ const sp<IBinder> display = data.readStrongBinder();
+ const status_t result = getDisplayInfo(display, &info);
+ reply->writeInt32(result);
+ if (result == NO_ERROR) {
+ memcpy(reply->writeInplace(sizeof(DisplayInfo)), &info, sizeof(DisplayInfo));
+ }
+ return NO_ERROR;
+ }
case GET_DISPLAY_CONFIGS: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- Vector<DisplayInfo> configs;
- sp<IBinder> display = data.readStrongBinder();
- status_t result = getDisplayConfigs(display, &configs);
+ Vector<DisplayConfig> configs;
+ const sp<IBinder> display = data.readStrongBinder();
+ const status_t result = getDisplayConfigs(display, &configs);
reply->writeInt32(result);
if (result == NO_ERROR) {
reply->writeUint32(static_cast<uint32_t>(configs.size()));
for (size_t c = 0; c < configs.size(); ++c) {
- memcpy(reply->writeInplace(sizeof(DisplayInfo)),
- &configs[c], sizeof(DisplayInfo));
+ memcpy(reply->writeInplace(sizeof(DisplayConfig)), &configs[c],
+ sizeof(DisplayConfig));
}
}
return NO_ERROR;
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index d5cf11d..23532e7 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -50,6 +50,17 @@
using ui::ColorMode;
using ui::Dataspace;
+namespace {
+
+bool isInterceptorRegistrationOp(int op) {
+ return op == NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR ||
+ op == NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR ||
+ op == NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR ||
+ op == NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR;
+}
+
+} // namespace
+
Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
: mGraphicBufferProducer(bufferProducer),
mCrop(Rect::EMPTY_RECT),
@@ -366,18 +377,58 @@
int Surface::hook_dequeueBuffer(ANativeWindow* window,
ANativeWindowBuffer** buffer, int* fenceFd) {
Surface* c = getSelf(window);
+ {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mDequeueInterceptor != nullptr) {
+ auto interceptor = c->mDequeueInterceptor;
+ auto data = c->mDequeueInterceptorData;
+ return interceptor(window, Surface::dequeueBufferInternal, data, buffer, fenceFd);
+ }
+ }
+ return c->dequeueBuffer(buffer, fenceFd);
+}
+
+int Surface::dequeueBufferInternal(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd) {
+ Surface* c = getSelf(window);
return c->dequeueBuffer(buffer, fenceFd);
}
int Surface::hook_cancelBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd) {
Surface* c = getSelf(window);
+ {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mCancelInterceptor != nullptr) {
+ auto interceptor = c->mCancelInterceptor;
+ auto data = c->mCancelInterceptorData;
+ return interceptor(window, Surface::cancelBufferInternal, data, buffer, fenceFd);
+ }
+ }
+ return c->cancelBuffer(buffer, fenceFd);
+}
+
+int Surface::cancelBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
return c->cancelBuffer(buffer, fenceFd);
}
int Surface::hook_queueBuffer(ANativeWindow* window,
ANativeWindowBuffer* buffer, int fenceFd) {
Surface* c = getSelf(window);
+ {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mQueueInterceptor != nullptr) {
+ auto interceptor = c->mQueueInterceptor;
+ auto data = c->mQueueInterceptorData;
+ return interceptor(window, Surface::queueBufferInternal, data, buffer, fenceFd);
+ }
+ }
+ return c->queueBuffer(buffer, fenceFd);
+}
+
+int Surface::queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd) {
+ Surface* c = getSelf(window);
return c->queueBuffer(buffer, fenceFd);
}
@@ -420,21 +471,38 @@
return c->queueBuffer(buffer, -1);
}
-int Surface::hook_query(const ANativeWindow* window,
- int what, int* value) {
- const Surface* c = getSelf(window);
- return c->query(what, value);
-}
-
int Surface::hook_perform(ANativeWindow* window, int operation, ...) {
va_list args;
va_start(args, operation);
Surface* c = getSelf(window);
- int result = c->perform(operation, args);
+ int result;
+ // Don't acquire shared ownership of the interceptor mutex if we're going to
+ // do interceptor registration, as otherwise we'll deadlock on acquiring
+ // exclusive ownership.
+ if (!isInterceptorRegistrationOp(operation)) {
+ std::shared_lock<std::shared_mutex> lock(c->mInterceptorMutex);
+ if (c->mPerformInterceptor != nullptr) {
+ result = c->mPerformInterceptor(window, Surface::performInternal,
+ c->mPerformInterceptorData, operation, args);
+ va_end(args);
+ return result;
+ }
+ }
+ result = c->perform(operation, args);
va_end(args);
return result;
}
+int Surface::performInternal(ANativeWindow* window, int operation, va_list args) {
+ Surface* c = getSelf(window);
+ return c->perform(operation, args);
+}
+
+int Surface::hook_query(const ANativeWindow* window, int what, int* value) {
+ const Surface* c = getSelf(window);
+ return c->query(what, value);
+}
+
int Surface::setSwapInterval(int interval) {
ATRACE_CALL();
// EGL specification states:
@@ -1096,6 +1164,22 @@
case NATIVE_WINDOW_SET_FRAME_RATE:
res = dispatchSetFrameRate(args);
break;
+ case NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR:
+ res = dispatchAddCancelInterceptor(args);
+ break;
+ case NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR:
+ res = dispatchAddDequeueInterceptor(args);
+ break;
+ case NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR:
+ res = dispatchAddPerformInterceptor(args);
+ break;
+ case NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR:
+ res = dispatchAddQueueInterceptor(args);
+ break;
+ case NATIVE_WINDOW_ALLOCATE_BUFFERS:
+ allocateBuffers();
+ res = NO_ERROR;
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1329,6 +1413,45 @@
return setFrameRate(frameRate);
}
+int Surface::dispatchAddCancelInterceptor(va_list args) {
+ ANativeWindow_cancelBufferInterceptor interceptor =
+ va_arg(args, ANativeWindow_cancelBufferInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mCancelInterceptor = interceptor;
+ mCancelInterceptorData = data;
+ return NO_ERROR;
+}
+
+int Surface::dispatchAddDequeueInterceptor(va_list args) {
+ ANativeWindow_dequeueBufferInterceptor interceptor =
+ va_arg(args, ANativeWindow_dequeueBufferInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mDequeueInterceptor = interceptor;
+ mDequeueInterceptorData = data;
+ return NO_ERROR;
+}
+
+int Surface::dispatchAddPerformInterceptor(va_list args) {
+ ANativeWindow_performInterceptor interceptor = va_arg(args, ANativeWindow_performInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mPerformInterceptor = interceptor;
+ mPerformInterceptorData = data;
+ return NO_ERROR;
+}
+
+int Surface::dispatchAddQueueInterceptor(va_list args) {
+ ANativeWindow_queueBufferInterceptor interceptor =
+ va_arg(args, ANativeWindow_queueBufferInterceptor);
+ void* data = va_arg(args, void*);
+ std::lock_guard<std::shared_mutex> lock(mInterceptorMutex);
+ mQueueInterceptor = interceptor;
+ mQueueInterceptorData = data;
+ return NO_ERROR;
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 63dc333..43bccf6 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -31,8 +31,6 @@
#include <system/graphics.h>
-#include <ui/DisplayInfo.h>
-
#include <gui/BufferItemConsumer.h>
#include <gui/CpuConsumer.h>
#include <gui/IGraphicBufferProducer.h>
@@ -41,6 +39,7 @@
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
#ifndef NO_INPUT
#include <input/InputWindow.h>
@@ -1623,15 +1622,23 @@
return sf->injectVSync(when);
}
-status_t SurfaceComposerClient::getDisplayConfigs(
- const sp<IBinder>& display, Vector<DisplayInfo>* configs)
-{
+status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display,
+ ui::DisplayState* state) {
+ return ComposerService::getComposerService()->getDisplayState(display, state);
+}
+
+status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
+ return ComposerService::getComposerService()->getDisplayInfo(display, info);
+}
+
+status_t SurfaceComposerClient::getDisplayConfigs(const sp<IBinder>& display,
+ Vector<DisplayConfig>* configs) {
return ComposerService::getComposerService()->getDisplayConfigs(display, configs);
}
-status_t SurfaceComposerClient::getDisplayInfo(const sp<IBinder>& display,
- DisplayInfo* info) {
- Vector<DisplayInfo> configs;
+status_t SurfaceComposerClient::getActiveDisplayConfig(const sp<IBinder>& display,
+ DisplayConfig* config) {
+ Vector<DisplayConfig> configs;
status_t result = getDisplayConfigs(display, &configs);
if (result != NO_ERROR) {
return result;
@@ -1643,7 +1650,7 @@
return NAME_NOT_FOUND;
}
- *info = configs[static_cast<size_t>(activeId)];
+ *config = configs[static_cast<size_t>(activeId)];
return NO_ERROR;
}
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 46c9f3a..e860f61 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_GUI_ISURFACE_COMPOSER_H
-#define ANDROID_GUI_ISURFACE_COMPOSER_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -46,13 +45,13 @@
#include <vector>
namespace android {
-// ----------------------------------------------------------------------------
struct client_cache_t;
struct ComposerState;
-struct DisplayState;
+struct DisplayConfig;
struct DisplayInfo;
struct DisplayStatInfo;
+struct DisplayState;
struct InputWindowCommands;
class LayerDebugInfo;
class HdrCapabilities;
@@ -63,6 +62,12 @@
class Rect;
enum class FrameEvent;
+namespace ui {
+
+struct DisplayState;
+
+} // namespace ui
+
/*
* This class defines the Binder IPC interface for accessing various
* SurfaceFlinger features.
@@ -161,10 +166,6 @@
*/
virtual void setPowerMode(const sp<IBinder>& display, int mode) = 0;
- /* returns information for each configuration of the given display
- * intended to be used to get information about built-in displays */
- virtual status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs) = 0;
/* returns display statistics for a given display
* intended to be used by the media framework to properly schedule
@@ -172,8 +173,25 @@
virtual status_t getDisplayStats(const sp<IBinder>& display,
DisplayStatInfo* stats) = 0;
- /* indicates which of the configurations returned by getDisplayInfo is
- * currently active */
+ /**
+ * Get transactional state of given display.
+ */
+ virtual status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*) = 0;
+
+ /**
+ * Get immutable information about given physical display.
+ */
+ virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*) = 0;
+
+ /**
+ * Get configurations supported by given physical display.
+ */
+ virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*) = 0;
+
+ /**
+ * Get the index into configurations returned by getDisplayConfigs,
+ * corresponding to the active configuration.
+ */
virtual int getActiveConfig(const sp<IBinder>& display) = 0;
virtual status_t getDisplayColorModes(const sp<IBinder>& display,
@@ -493,7 +511,7 @@
// Java by ActivityManagerService.
BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION,
CREATE_CONNECTION,
- CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED, // unused, fails permissions check
+ GET_DISPLAY_INFO,
CREATE_DISPLAY_EVENT_CONNECTION,
CREATE_DISPLAY,
DESTROY_DISPLAY,
@@ -503,7 +521,7 @@
GET_SUPPORTED_FRAME_TIMESTAMPS,
GET_DISPLAY_CONFIGS,
GET_ACTIVE_CONFIG,
- CONNECT_DISPLAY_UNUSED, // unused, fails permissions check
+ GET_DISPLAY_STATE,
CAPTURE_SCREEN,
CAPTURE_LAYERS,
CLEAR_ANIMATION_FRAME_STATS,
@@ -546,8 +564,4 @@
Parcel* reply, uint32_t flags = 0);
};
-// ----------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_ISURFACE_COMPOSER_H
+} // namespace android
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 86cc61f..0139507 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -21,16 +21,15 @@
#include <gui/HdrMetadata.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
-
+#include <system/window.h>
#include <ui/ANativeObjectBase.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
-
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
-#include <system/window.h>
+#include <shared_mutex>
namespace android {
@@ -205,6 +204,13 @@
ANativeWindowBuffer* buffer, int fenceFd);
static int hook_setSwapInterval(ANativeWindow* window, int interval);
+ static int cancelBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd);
+ static int dequeueBufferInternal(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+ static int performInternal(ANativeWindow* window, int operation, va_list args);
+ static int queueBufferInternal(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
+
static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
ANativeWindowBuffer* buffer);
static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
@@ -252,6 +258,10 @@
int dispatchGetLastDequeueDuration(va_list args);
int dispatchGetLastQueueDuration(va_list args);
int dispatchSetFrameRate(va_list args);
+ int dispatchAddCancelInterceptor(va_list args);
+ int dispatchAddDequeueInterceptor(va_list args);
+ int dispatchAddPerformInterceptor(va_list args);
+ int dispatchAddQueueInterceptor(va_list args);
bool transformToDisplayInverse();
protected:
@@ -457,6 +467,18 @@
// member variables are accessed.
mutable Mutex mMutex;
+ // mInterceptorMutex is the mutex guarding interceptors.
+ std::shared_mutex mInterceptorMutex;
+
+ ANativeWindow_cancelBufferInterceptor mCancelInterceptor = nullptr;
+ void* mCancelInterceptorData = nullptr;
+ ANativeWindow_dequeueBufferInterceptor mDequeueInterceptor = nullptr;
+ void* mDequeueInterceptorData = nullptr;
+ ANativeWindow_performInterceptor mPerformInterceptor = nullptr;
+ void* mPerformInterceptorData = nullptr;
+ ANativeWindow_queueBufferInterceptor mQueueInterceptor = nullptr;
+ void* mQueueInterceptorData = nullptr;
+
// must be used from the lock/unlock thread
sp<GraphicBuffer> mLockedBuffer;
sp<GraphicBuffer> mPostedBuffer;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 08e6a5a..6eec2b7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
-#define ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -46,17 +45,12 @@
namespace android {
-// ---------------------------------------------------------------------------
-
-struct DisplayInfo;
class HdrCapabilities;
class ISurfaceComposerClient;
class IGraphicBufferProducer;
class IRegionSamplingListener;
class Region;
-// ---------------------------------------------------------------------------
-
struct SurfaceControlStats {
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
const sp<Fence>& prevReleaseFence, uint32_t hint)
@@ -102,18 +96,21 @@
status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
void* cookie = nullptr, uint32_t flags = 0);
- // Get a list of supported configurations for a given display
- static status_t getDisplayConfigs(const sp<IBinder>& display,
- Vector<DisplayInfo>* configs);
+ // Get transactional state of given display.
+ static status_t getDisplayState(const sp<IBinder>& display, ui::DisplayState*);
- // Get the DisplayInfo for the currently-active configuration
- static status_t getDisplayInfo(const sp<IBinder>& display,
- DisplayInfo* info);
+ // Get immutable information about given physical display.
+ static status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*);
- // Get the index of the current active configuration (relative to the list
- // returned by getDisplayInfo)
+ // Get configurations supported by given physical display.
+ static status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*);
+
+ // Get the ID of the active DisplayConfig, as getDisplayConfigs index.
static int getActiveConfig(const sp<IBinder>& display);
+ // Shorthand for getDisplayConfigs element at getActiveConfig index.
+ static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
+
// Sets the refresh rate boundaries for display configuration.
// For all other parameters, default configuration is used. The index for the default is
// corresponting to the configs returned from getDisplayConfigs().
@@ -644,8 +641,4 @@
void onTransactionCompleted(ListenerStats stats) override;
};
-// ---------------------------------------------------------------------------
-
-}; // namespace android
-
-#endif // ANDROID_GUI_SURFACE_COMPOSER_CLIENT_H
+} // namespace android
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 41f0d40..a273914 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -25,7 +25,7 @@
#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <ui/GraphicBuffer.h>
#include <ui/GraphicTypes.h>
#include <ui/Transform.h>
@@ -103,10 +103,11 @@
t.apply();
t.clear();
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplayToken, &info));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &config));
+ const ui::Size& resolution = config.resolution;
+ mDisplayWidth = resolution.getWidth();
+ mDisplayHeight = resolution.getHeight();
mSurfaceControl = mClient->createSurface(String8("TestSurface"), mDisplayWidth,
mDisplayHeight, PIXEL_FORMAT_RGBA_8888,
@@ -114,7 +115,7 @@
/*parent*/ nullptr);
t.setLayerStack(mSurfaceControl, 0)
.setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
- .setFrame(mSurfaceControl, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setFrame(mSurfaceControl, Rect(resolution))
.show(mSurfaceControl)
.setDataspace(mSurfaceControl, ui::Dataspace::V0_SRGB)
.apply();
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 04749e6..1a623e2 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -41,7 +41,7 @@
#include <input/InputTransport.h>
#include <input/Input.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -223,13 +223,13 @@
const auto display = mComposerClient->getInternalDisplayToken();
ASSERT_NE(display, nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, mComposerClient->getActiveDisplayConfig(display, &config));
// After a new buffer is queued, SurfaceFlinger is notified and will
// latch the new buffer on next vsync. Let's heuristically wait for 3
// vsyncs.
- mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
+ mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
}
void TearDown() {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 25c032f..70fd888 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -718,8 +718,15 @@
}
void setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override {}
- status_t getDisplayConfigs(const sp<IBinder>& /*display*/,
- Vector<DisplayInfo>* /*configs*/) override { return NO_ERROR; }
+ status_t getDisplayInfo(const sp<IBinder>& /*display*/, DisplayInfo*) override {
+ return NO_ERROR;
+ }
+ status_t getDisplayConfigs(const sp<IBinder>& /*display*/, Vector<DisplayConfig>*) override {
+ return NO_ERROR;
+ }
+ status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
+ return NO_ERROR;
+ }
status_t getDisplayStats(const sp<IBinder>& /*display*/,
DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index bff1b97..85b0fd0 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -57,7 +57,7 @@
return "UNKNOWN";
}
-void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId,
+void InputEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac) {
mDeviceId = deviceId;
mSource = source;
@@ -82,7 +82,7 @@
return getKeyCodeByLabel(label);
}
-void KeyEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId,
+void KeyEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t flags,
int32_t keyCode, int32_t scanCode, int32_t metaState, int32_t repeatCount,
nsecs_t downTime, nsecs_t eventTime) {
@@ -245,7 +245,7 @@
// --- MotionEvent ---
-void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId,
+void MotionEvent::initialize(int32_t deviceId, uint32_t source, int32_t displayId,
std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton,
int32_t flags, int32_t edgeFlags, int32_t metaState,
int32_t buttonState, MotionClassification classification, float xScale,
@@ -321,17 +321,17 @@
float MotionEvent::getXCursorPosition() const {
const float rawX = getRawXCursorPosition();
- return rawX + mXOffset;
+ return rawX * mXScale + mXOffset;
}
float MotionEvent::getYCursorPosition() const {
const float rawY = getRawYCursorPosition();
- return rawY + mYOffset;
+ return rawY * mYScale + mYOffset;
}
void MotionEvent::setCursorPosition(float x, float y) {
- mRawXCursorPosition = x - mXOffset;
- mRawYCursorPosition = y - mYOffset;
+ mRawXCursorPosition = (x - mXOffset) / mXScale;
+ mRawYCursorPosition = (y - mYOffset) / mYScale;
}
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
@@ -346,9 +346,9 @@
float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis);
switch (axis) {
case AMOTION_EVENT_AXIS_X:
- return value + mXOffset;
+ return value * mXScale + mXOffset;
case AMOTION_EVENT_AXIS_Y:
- return value + mYOffset;
+ return value * mYScale + mYOffset;
}
return value;
}
@@ -368,9 +368,9 @@
float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis);
switch (axis) {
case AMOTION_EVENT_AXIS_X:
- return value + mXOffset;
+ return value * mXScale + mXOffset;
case AMOTION_EVENT_AXIS_Y:
- return value + mYOffset;
+ return value * mYScale + mYOffset;
}
return value;
}
@@ -442,11 +442,11 @@
float oldXOffset = mXOffset;
float oldYOffset = mYOffset;
float newX, newY;
- float rawX = getRawX(0);
- float rawY = getRawY(0);
- transformPoint(matrix, rawX + oldXOffset, rawY + oldYOffset, &newX, &newY);
- mXOffset = newX - rawX;
- mYOffset = newY - rawY;
+ float scaledRawX = getRawX(0) * mXScale;
+ float scaledRawY = getRawY(0) * mYScale;
+ transformPoint(matrix, scaledRawX + oldXOffset, scaledRawY + oldYOffset, &newX, &newY);
+ mXOffset = newX - scaledRawX;
+ mYOffset = newY - scaledRawY;
// Determine how the origin is transformed by the matrix so that we
// can transform orientation vectors.
@@ -455,22 +455,22 @@
// Apply the transformation to cursor position.
if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
- float x = mRawXCursorPosition + oldXOffset;
- float y = mRawYCursorPosition + oldYOffset;
+ float x = mRawXCursorPosition * mXScale + oldXOffset;
+ float y = mRawYCursorPosition * mYScale + oldYOffset;
transformPoint(matrix, x, y, &x, &y);
- mRawXCursorPosition = x - mXOffset;
- mRawYCursorPosition = y - mYOffset;
+ mRawXCursorPosition = (x - mXOffset) / mXScale;
+ mRawYCursorPosition = (y - mYOffset) / mYScale;
}
// Apply the transformation to all samples.
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
PointerCoords& c = mSamplePointerCoords.editItemAt(i);
- float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
- float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
+ float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) * mXScale + oldXOffset;
+ float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) * mYScale + oldYOffset;
transformPoint(matrix, x, y, &x, &y);
- c.setAxisValue(AMOTION_EVENT_AXIS_X, x - mXOffset);
- c.setAxisValue(AMOTION_EVENT_AXIS_Y, y - mYOffset);
+ c.setAxisValue(AMOTION_EVENT_AXIS_X, (x - mXOffset) / mXScale);
+ c.setAxisValue(AMOTION_EVENT_AXIS_Y, (y - mYOffset) / mYScale);
float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
@@ -488,7 +488,7 @@
}
mDeviceId = parcel->readInt32();
- mSource = parcel->readInt32();
+ mSource = parcel->readUint32();
mDisplayId = parcel->readInt32();
std::vector<uint8_t> hmac;
status_t result = parcel->readByteVector(&hmac);
@@ -549,7 +549,7 @@
parcel->writeInt32(sampleCount);
parcel->writeInt32(mDeviceId);
- parcel->writeInt32(mSource);
+ parcel->writeUint32(mSource);
parcel->writeInt32(mDisplayId);
std::vector<uint8_t> hmac(mHmac.begin(), mHmac.end());
parcel->writeByteVector(hmac);
@@ -590,7 +590,7 @@
}
#endif
-bool MotionEvent::isTouchEvent(int32_t source, int32_t action) {
+bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) {
if (source & AINPUT_SOURCE_CLASS_POINTER) {
// Specifically excludes HOVER_MOVE and SCROLL.
switch (action & AMOTION_EVENT_ACTION_MASK) {
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 8c6890f..dce1f29 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -189,7 +189,7 @@
ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
ASSERT_EQ(2, event.getDeviceId());
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource());
+ ASSERT_EQ(AINPUT_SOURCE_GAMEPAD, event.getSource());
ASSERT_EQ(DISPLAY_ID, event.getDisplayId());
EXPECT_EQ(HMAC, event.getHmac());
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
@@ -203,7 +203,7 @@
// Set source.
event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+ ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
// Set display id.
constexpr int32_t newDisplayId = 2;
@@ -311,7 +311,7 @@
// Check properties.
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
ASSERT_EQ(2, event->getDeviceId());
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource());
+ ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, event->getSource());
ASSERT_EQ(DISPLAY_ID, event->getDisplayId());
EXPECT_EQ(HMAC, event->getHmac());
ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
@@ -375,19 +375,19 @@
ASSERT_EQ(211, event->getRawY(0));
ASSERT_EQ(221, event->getRawY(1));
- ASSERT_EQ(X_OFFSET + 10, event->getHistoricalX(0, 0));
- ASSERT_EQ(X_OFFSET + 20, event->getHistoricalX(1, 0));
- ASSERT_EQ(X_OFFSET + 110, event->getHistoricalX(0, 1));
- ASSERT_EQ(X_OFFSET + 120, event->getHistoricalX(1, 1));
- ASSERT_EQ(X_OFFSET + 210, event->getX(0));
- ASSERT_EQ(X_OFFSET + 220, event->getX(1));
+ ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0));
+ ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0));
+ ASSERT_EQ(X_OFFSET + 110 * X_SCALE, event->getHistoricalX(0, 1));
+ ASSERT_EQ(X_OFFSET + 120 * X_SCALE, event->getHistoricalX(1, 1));
+ ASSERT_EQ(X_OFFSET + 210 * X_SCALE, event->getX(0));
+ ASSERT_EQ(X_OFFSET + 220 * X_SCALE, event->getX(1));
- ASSERT_EQ(Y_OFFSET + 11, event->getHistoricalY(0, 0));
- ASSERT_EQ(Y_OFFSET + 21, event->getHistoricalY(1, 0));
- ASSERT_EQ(Y_OFFSET + 111, event->getHistoricalY(0, 1));
- ASSERT_EQ(Y_OFFSET + 121, event->getHistoricalY(1, 1));
- ASSERT_EQ(Y_OFFSET + 211, event->getY(0));
- ASSERT_EQ(Y_OFFSET + 221, event->getY(1));
+ ASSERT_EQ(Y_OFFSET + 11 * Y_SCALE, event->getHistoricalY(0, 0));
+ ASSERT_EQ(Y_OFFSET + 21 * Y_SCALE, event->getHistoricalY(1, 0));
+ ASSERT_EQ(Y_OFFSET + 111 * Y_SCALE, event->getHistoricalY(0, 1));
+ ASSERT_EQ(Y_OFFSET + 121 * Y_SCALE, event->getHistoricalY(1, 1));
+ ASSERT_EQ(Y_OFFSET + 211 * Y_SCALE, event->getY(0));
+ ASSERT_EQ(Y_OFFSET + 221 * Y_SCALE, event->getY(1));
ASSERT_EQ(12, event->getHistoricalPressure(0, 0));
ASSERT_EQ(22, event->getHistoricalPressure(1, 0));
@@ -448,7 +448,7 @@
// Set source.
event.setSource(AINPUT_SOURCE_JOYSTICK);
- ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+ ASSERT_EQ(AINPUT_SOURCE_JOYSTICK, event.getSource());
// Set displayId.
constexpr int32_t newDisplayId = 2;
@@ -513,8 +513,8 @@
ASSERT_EQ(210 * 2, event.getRawX(0));
ASSERT_EQ(211 * 2, event.getRawY(0));
- ASSERT_EQ((X_OFFSET + 210) * 2, event.getX(0));
- ASSERT_EQ((Y_OFFSET + 211) * 2, event.getY(0));
+ ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0));
+ ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0));
ASSERT_EQ(212, event.getPressure(0));
ASSERT_EQ(213, event.getSize(0));
ASSERT_EQ(214 * 2, event.getTouchMajor(0));
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 1e51ea8..d4bbf6c 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -73,7 +73,7 @@
constexpr uint32_t seq = 15;
constexpr int32_t deviceId = 1;
- constexpr int32_t source = AINPUT_SOURCE_KEYBOARD;
+ constexpr uint32_t source = AINPUT_SOURCE_KEYBOARD;
constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
constexpr std::array<uint8_t, 32> hmac = {31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,
@@ -139,7 +139,7 @@
constexpr uint32_t seq = 15;
constexpr int32_t deviceId = 1;
- constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+ constexpr uint32_t source = AINPUT_SOURCE_TOUCHSCREEN;
constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
constexpr std::array<uint8_t, 32> hmac = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
@@ -221,8 +221,8 @@
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition());
EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
- EXPECT_EQ(xCursorPosition + xOffset, motionEvent->getXCursorPosition());
- EXPECT_EQ(yCursorPosition + yOffset, motionEvent->getYCursorPosition());
+ EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
+ EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(eventTime, motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
@@ -237,10 +237,10 @@
motionEvent->getRawX(i));
EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
motionEvent->getRawY(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
- motionEvent->getX(i));
- EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
- motionEvent->getY(i));
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) * xScale + xOffset,
+ motionEvent->getX(i));
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) * yScale + yOffset,
+ motionEvent->getY(i));
EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
motionEvent->getPressure(i));
EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 15d937e..58fff8f 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -60,7 +60,7 @@
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
- void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb);
+ void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
enum {
MSG_SCHEDULE_CALLBACKS = 0,
@@ -152,21 +152,34 @@
void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
{
AutoMutex _l{mLock};
+ for (const auto& callback : mRefreshRateCallbacks) {
+ // Don't re-add callbacks.
+ if (cb == callback.callback && data == callback.data) {
+ return;
+ }
+ }
mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
}
}
-void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb) {
+void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb,
+ void* data) {
{
AutoMutex _l{mLock};
mRefreshRateCallbacks.erase(std::remove_if(mRefreshRateCallbacks.begin(),
mRefreshRateCallbacks.end(),
[&](const RefreshRateCallback& callback) {
- return cb == callback.callback;
- }));
+ return cb == callback.callback &&
+ data == callback.data;
+ }),
+ mRefreshRateCallbacks.end());
if (mRefreshRateCallbacks.empty()) {
toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
+ // If callbacks are empty then clear out the most recently seen
+ // vsync period so that when another callback is registered then the
+ // up-to-date refresh rate can be communicated to the app again.
+ mVsyncPeriod = 0;
}
}
}
@@ -224,9 +237,9 @@
// on every single configuration change.
if (mVsyncPeriod != vsyncPeriod) {
cb.callback(vsyncPeriod, cb.data);
- mVsyncPeriod = vsyncPeriod;
}
}
+ mVsyncPeriod = vsyncPeriod;
}
}
@@ -285,8 +298,9 @@
AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
}
void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
- AChoreographer_refreshRateCallback callback) {
- AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback);
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback, data);
}
AChoreographer* AChoreographer_create() {
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index 1e25049..277635c 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -16,6 +16,7 @@
#include <apex/display.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/PixelFormat.h>
@@ -116,17 +117,12 @@
LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument");
namespace {
+
sp<IBinder> getToken(ADisplay* display) {
DisplayImpl* impl = reinterpret_cast<DisplayImpl*>(display);
return SurfaceComposerClient::getPhysicalDisplayToken(impl->id);
}
-int64_t computeSfOffset(const DisplayInfo& info) {
- // This should probably be part of the config instead of extrapolated from
- // the presentation deadline and fudged here, but the way the math works out
- // here we do get the right offset.
- return static_cast<int64_t>((1000000000 / info.fps) - info.presentationDeadline + 1000000);
-}
} // namespace
namespace android {
@@ -142,9 +138,16 @@
int numConfigs = 0;
for (int i = 0; i < size; ++i) {
const sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]);
- Vector<DisplayInfo> configs;
- const status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
- if (status != OK) {
+
+ DisplayInfo info;
+ if (const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info);
+ status != OK) {
+ return status;
+ }
+
+ Vector<DisplayConfig> configs;
+ if (const status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
+ status != OK) {
return status;
}
if (configs.empty()) {
@@ -154,11 +157,11 @@
numConfigs += configs.size();
configsPerDisplay[i].reserve(configs.size());
for (int j = 0; j < configs.size(); ++j) {
- const DisplayInfo config = configs[j];
+ const DisplayConfig& config = configs[j];
configsPerDisplay[i].emplace_back(
- DisplayConfigImpl{static_cast<int32_t>(config.w),
- static_cast<int32_t>(config.h), config.density, config.fps,
- computeSfOffset(config), config.appVsyncOffset});
+ DisplayConfigImpl{config.resolution.getWidth(), config.resolution.getHeight(),
+ info.density, config.refreshRate, config.sfVsyncOffset,
+ config.appVsyncOffset});
}
}
diff --git a/libs/nativedisplay/include/android/choreographer.h b/libs/nativedisplay/include/android/choreographer.h
index 0d97e8c..5fd3de9 100644
--- a/libs/nativedisplay/include/android/choreographer.h
+++ b/libs/nativedisplay/include/android/choreographer.h
@@ -54,6 +54,13 @@
*/
typedef void (*AChoreographer_frameCallback64)(int64_t frameTimeNanos, void* data);
+/**
+ * Prototype of the function that is called when the display refresh rate
+ * changes. It's passed the new vsync period in nanoseconds, as well as the data
+ * pointer provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
+
#if __ANDROID_API__ >= 24
/**
@@ -102,6 +109,42 @@
#endif /* __ANDROID_API__ >= 29 */
+#if __ANDROID_API__ >= 30
+
+/**
+ * Registers a callback to be run when the display refresh rate changes. The
+ * data pointer provided will be passed to the callback function when it's
+ * called. The same callback may be registered multiple times, provided that a
+ * different data pointer is provided each time.
+ *
+ * If an application registers a callback for this choreographer instance when
+ * no new callbacks were previously registered, that callback is guaranteed to
+ * be dispatched. However, if the callback and associated data pointer are
+ * unregistered prior to running the callback, then the callback may be silently
+ * dropped.
+ *
+ * This api is thread-safe. Any thread is allowed to register a new refresh
+ * rate callback for the choreographer instance.
+ */
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback, void* data);
+
+/**
+ * Unregisters a callback to be run when the display refresh rate changes, along
+ * with the data pointer previously provided when registering the callback. The
+ * callback is only unregistered when the data pointer matches one that was
+ * previously registered.
+ *
+ * This api is thread-safe. Any thread is allowed to unregister an existing
+ * refresh rate callback for the choreographer instance. When a refresh rate
+ * callback and associated data pointer are unregistered, then there is a
+ * guarantee that when the unregistration completes that that callback will not
+ * be run with the data pointer passed.
+ */
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback, void* data);
+#endif /* __ANDROID_API__ >= 30 */
+
__END_DECLS
#endif // ANDROID_CHOREOGRAPHER_H
diff --git a/libs/nativedisplay/include/apex/choreographer.h b/libs/nativedisplay/include/apex/choreographer.h
index 5251fd3..b17b497 100644
--- a/libs/nativedisplay/include/apex/choreographer.h
+++ b/libs/nativedisplay/include/apex/choreographer.h
@@ -22,25 +22,6 @@
__BEGIN_DECLS
/**
- * Prototype of the function that is called when the display refresh rate
- * changes. It's passed the new vsync period in nanoseconds, as well as the data
- * pointer provided by the application that registered a callback.
- */
-typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
-
-/**
- * Registers a callback to be run when the display refresh rate changes.
- */
-void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
- AChoreographer_refreshRateCallback, void* data);
-
-/**
- * Unregisters a callback to be run when the display refresh rate changes.
- */
-void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
- AChoreographer_refreshRateCallback);
-
-/**
* Creates an instance of AChoreographer.
*
* The key differences between this method and AChoreographer_getInstance are:
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index a60bc4d..a1c9eb8 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -304,3 +304,34 @@
int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) {
return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, timeout);
}
+
+int ANativeWindow_setCancelBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_cancelBufferInterceptor interceptor,
+ void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR, interceptor, data);
+}
+
+int ANativeWindow_setDequeueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_dequeueBufferInterceptor interceptor,
+ void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR, interceptor, data);
+}
+
+int ANativeWindow_setPerformInterceptor(ANativeWindow* window,
+ ANativeWindow_performInterceptor interceptor, void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR, interceptor, data);
+}
+
+int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_queueBufferInterceptor interceptor,
+ void* data) {
+ return window->perform(window, NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR, interceptor, data);
+}
+
+void ANativeWindow_allocateBuffers(ANativeWindow* window) {
+ window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS);
+}
+
+int64_t ANativeWindow_getNextFrameId(ANativeWindow* window) {
+ return query64(window, NATIVE_WINDOW_GET_NEXT_FRAME_ID);
+}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
index 869b22e..02b886c 100644
--- a/libs/nativewindow/include/apex/window.h
+++ b/libs/nativewindow/include/apex/window.h
@@ -17,12 +17,159 @@
#pragma once
#include <nativebase/nativebase.h>
+#include <stdarg.h>
// apex is a superset of the NDK
#include <android/native_window.h>
__BEGIN_DECLS
+/*
+ * perform bits that can be used with ANativeWindow_perform()
+ *
+ * This is only to support the intercepting methods below - these should notbe
+ * used directly otherwise.
+ */
+enum ANativeWindowPerform {
+ // clang-format off
+ ANATIVEWINDOW_PERFORM_SET_USAGE = 0,
+ ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY = 5,
+ ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT = 9,
+ ANATIVEWINDOW_PERFORM_SET_USAGE64 = 30,
+ // clang-format on
+};
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_cancelBuffer is called.
+ */
+typedef int (*ANativeWindow_cancelBufferFn)(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_cancelBufferFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_cancelBufferFn if it were to be called.
+ */
+typedef int (*ANativeWindow_cancelBufferInterceptor)(ANativeWindow* window,
+ ANativeWindow_cancelBufferFn cancelBuffer,
+ void* data, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_dequeueBuffer is called.
+ */
+typedef int (*ANativeWindow_dequeueBufferFn)(ANativeWindow* window, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_dequeueBufferFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_dequeueBufferFn if it were to be called.
+ */
+typedef int (*ANativeWindow_dequeueBufferInterceptor)(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer,
+ void* data, ANativeWindowBuffer** buffer,
+ int* fenceFd);
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_perform is called.
+ */
+typedef int (*ANativeWindow_performFn)(ANativeWindow* window, int operation, va_list args);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_performFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_performFn if it were to be called.
+ */
+typedef int (*ANativeWindow_performInterceptor)(ANativeWindow* window,
+ ANativeWindow_performFn perform, void* data,
+ int operation, va_list args);
+
+/**
+ * Prototype of the function that an ANativeWindow implementation would call
+ * when ANativeWindow_queueBuffer is called.
+ */
+typedef int (*ANativeWindow_queueBufferFn)(ANativeWindow* window, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Prototype of the function that intercepts an invocation of
+ * ANativeWindow_queueBufferFn, along with a data pointer that's passed by the
+ * caller who set the interceptor, as well as arguments that would be
+ * passed to ANativeWindow_queueBufferFn if it were to be called.
+ */
+typedef int (*ANativeWindow_queueBufferInterceptor)(ANativeWindow* window,
+ ANativeWindow_queueBufferFn queueBuffer,
+ void* data, ANativeWindowBuffer* buffer,
+ int fenceFd);
+
+/**
+ * Registers an interceptor for ANativeWindow_cancelBuffer. Instead of calling
+ * the underlying cancelBuffer function, instead the provided interceptor is
+ * called, which may optionally call the underlying cancelBuffer function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setCancelBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_cancelBufferInterceptor interceptor,
+ void* data);
+
+/**
+ * Registers an interceptor for ANativeWindow_dequeueBuffer. Instead of calling
+ * the underlying dequeueBuffer function, instead the provided interceptor is
+ * called, which may optionally call the underlying dequeueBuffer function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setDequeueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_dequeueBufferInterceptor interceptor,
+ void* data);
+/**
+ * Registers an interceptor for ANativeWindow_perform. Instead of calling
+ * the underlying perform function, instead the provided interceptor is
+ * called, which may optionally call the underlying perform function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setPerformInterceptor(ANativeWindow* window,
+ ANativeWindow_performInterceptor interceptor, void* data);
+/**
+ * Registers an interceptor for ANativeWindow_queueBuffer. Instead of calling
+ * the underlying queueBuffer function, instead the provided interceptor is
+ * called, which may optionally call the underlying queueBuffer function. An
+ * optional data pointer is also provided to side-channel additional arguments.
+ *
+ * Note that usage of this should only be used for specialized use-cases by
+ * either the system partition or to Mainline modules. This should never be
+ * exposed to NDK or LL-NDK.
+ *
+ * Returns NO_ERROR on success, -errno if registration failed.
+ */
+int ANativeWindow_setQueueBufferInterceptor(ANativeWindow* window,
+ ANativeWindow_queueBufferInterceptor interceptor,
+ void* data);
+
/**
* Retrieves how long it took for the last time a buffer was dequeued.
*
@@ -53,8 +200,23 @@
* made by the window will return -ETIMEDOUT after the timeout if the dequeue
* takes too long.
*
- * \return NO_ERROR on succes, -errno on error.
+ * \return NO_ERROR on success, -errno on error.
*/
int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout);
+/**
+ * Provides a hint to the window that buffers should be preallocated ahead of
+ * time. Note that the window implementation is not guaranteed to preallocate
+ * any buffers, for instance if a private API disallows allocation of new
+ * buffers. As such no success/error status is returned.
+ */
+void ANativeWindow_allocateBuffers(ANativeWindow* window);
+
+/**
+ * Retrieves an identifier for the next frame to be queued by this window.
+ *
+ * \return -errno on error, otherwise returns the next frame id.
+ */
+int64_t ANativeWindow_getNextFrameId(ANativeWindow* window);
+
__END_DECLS
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 14f7214..121374b 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -207,16 +207,16 @@
*/
enum {
// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
+ NATIVE_WINDOW_SET_USAGE = ANATIVEWINDOW_PERFORM_SET_USAGE, /* deprecated */
NATIVE_WINDOW_CONNECT = 1, /* deprecated */
NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
NATIVE_WINDOW_SET_CROP = 3, /* private */
NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
+ NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY, /* deprecated */
NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
+ NATIVE_WINDOW_SET_BUFFERS_FORMAT = ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT,
NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
NATIVE_WINDOW_LOCK = 11, /* private */
NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
@@ -237,7 +237,7 @@
NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
- NATIVE_WINDOW_SET_USAGE64 = 30,
+ NATIVE_WINDOW_SET_USAGE64 = ANATIVEWINDOW_PERFORM_SET_USAGE64,
NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
@@ -248,6 +248,11 @@
NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */
NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */
NATIVE_WINDOW_SET_FRAME_RATE = 40,
+ NATIVE_WINDOW_SET_CANCEL_INTERCEPTOR = 41, /* private */
+ NATIVE_WINDOW_SET_DEQUEUE_INTERCEPTOR = 42, /* private */
+ NATIVE_WINDOW_SET_PERFORM_INTERCEPTOR = 43, /* private */
+ NATIVE_WINDOW_SET_QUEUE_INTERCEPTOR = 44, /* private */
+ NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */
// clang-format on
};
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 3002da2..e0e20c3 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -17,6 +17,7 @@
ANativeWindow_OemStorageGet; # llndk
ANativeWindow_OemStorageSet; # llndk
ANativeWindow_acquire;
+ ANativeWindow_allocateBuffers; # apex # introduced=30
ANativeWindow_cancelBuffer; # llndk
ANativeWindow_dequeueBuffer; # llndk
ANativeWindow_getBuffersDataSpace; # introduced=28
@@ -25,11 +26,16 @@
ANativeWindow_getLastDequeueDuration; # apex # introduced=30
ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
ANativeWindow_getLastQueueDuration; # apex # introduced=30
+ ANativeWindow_getNextFrameId; # apex # introduced=30
ANativeWindow_getWidth;
ANativeWindow_lock;
ANativeWindow_query; # llndk
ANativeWindow_queryf; # llndk
ANativeWindow_queueBuffer; # llndk
+ ANativeWindow_setCancelBufferInterceptor; # apex # introduced=30
+ ANativeWindow_setDequeueBufferInterceptor; # apex # introduced=30
+ ANativeWindow_setPerformInterceptor; # apex # introduced=30
+ ANativeWindow_setQueueBufferInterceptor; # apex # introduced=30
ANativeWindow_release;
ANativeWindow_setAutoPrerotation; # llndk
ANativeWindow_setAutoRefresh; # llndk
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 2e3ab4c..4c7b629 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -52,6 +52,7 @@
"gl/GLExtensions.cpp",
"gl/GLFramebuffer.cpp",
"gl/GLImage.cpp",
+ "gl/GLShadowTexture.cpp",
"gl/GLShadowVertexGenerator.cpp",
"gl/GLSkiaShadowPort.cpp",
"gl/ImageManager.cpp",
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 98605ba..69003fb 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -1661,6 +1661,7 @@
mState.cornerRadius = 0.0f;
mState.drawShadows = true;
+ setupLayerTexturing(mShadowTexture.getTexture());
drawMesh(mesh);
mState.drawShadows = false;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 45c85de..4fc457f 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -32,6 +32,7 @@
#include <renderengine/RenderEngine.h>
#include <renderengine/private/Description.h>
#include <sys/types.h>
+#include "GLShadowTexture.h"
#include "ImageManager.h"
#define EGL_NO_CONFIG ((EGLConfig)0)
@@ -183,6 +184,7 @@
GLuint mVpWidth;
GLuint mVpHeight;
Description mState;
+ GLShadowTexture mShadowTexture;
mat4 mSrgbToXyz;
mat4 mDisplayP3ToXyz;
diff --git a/libs/renderengine/gl/GLShadowTexture.cpp b/libs/renderengine/gl/GLShadowTexture.cpp
new file mode 100644
index 0000000..2423a34
--- /dev/null
+++ b/libs/renderengine/gl/GLShadowTexture.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include "GLShadowTexture.h"
+#include "GLSkiaShadowPort.h"
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+GLShadowTexture::GLShadowTexture() {
+ fillShadowTextureData(mTextureData, SHADOW_TEXTURE_WIDTH);
+
+ glGenTextures(1, &mName);
+ glBindTexture(GL_TEXTURE_2D, mName);
+ glTexImage2D(GL_TEXTURE_2D, 0 /* base image level */, GL_ALPHA, SHADOW_TEXTURE_WIDTH,
+ SHADOW_TEXTURE_HEIGHT, 0 /* border */, GL_ALPHA, GL_UNSIGNED_BYTE, mTextureData);
+ mTexture.init(Texture::TEXTURE_2D, mName);
+ mTexture.setFiltering(true);
+ mTexture.setDimensions(SHADOW_TEXTURE_WIDTH, 1);
+}
+
+GLShadowTexture::~GLShadowTexture() {
+ glDeleteTextures(1, &mName);
+}
+
+const Texture& GLShadowTexture::getTexture() {
+ return mTexture;
+}
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLShadowTexture.h b/libs/renderengine/gl/GLShadowTexture.h
new file mode 100644
index 0000000..250a9d7
--- /dev/null
+++ b/libs/renderengine/gl/GLShadowTexture.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <renderengine/Texture.h>
+#include <cstdint>
+
+namespace android {
+namespace renderengine {
+namespace gl {
+
+class GLShadowTexture {
+public:
+ GLShadowTexture();
+ ~GLShadowTexture();
+
+ const Texture& getTexture();
+
+private:
+ static constexpr int SHADOW_TEXTURE_WIDTH = 128;
+ static constexpr int SHADOW_TEXTURE_HEIGHT = 1;
+
+ GLuint mName;
+ Texture mTexture;
+ uint8_t mTextureData[SHADOW_TEXTURE_WIDTH];
+};
+
+} // namespace gl
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/gl/GLSkiaShadowPort.cpp b/libs/renderengine/gl/GLSkiaShadowPort.cpp
index 224ce6c..da8b435 100644
--- a/libs/renderengine/gl/GLSkiaShadowPort.cpp
+++ b/libs/renderengine/gl/GLSkiaShadowPort.cpp
@@ -644,6 +644,13 @@
2.0f * devSpaceSpotBlur, std::abs(insetWidth));
}
+void fillShadowTextureData(uint8_t* data, size_t shadowTextureWidth) {
+ for (int i = 0; i < shadowTextureWidth; i++) {
+ const float d = 1 - i / ((shadowTextureWidth * 1.0f) - 1.0f);
+ data[i] = static_cast<uint8_t>((exp(-4.0f * d * d) - 0.018f) * 255);
+ }
+}
+
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/GLSkiaShadowPort.h b/libs/renderengine/gl/GLSkiaShadowPort.h
index e7d1861..912c8bb 100644
--- a/libs/renderengine/gl/GLSkiaShadowPort.h
+++ b/libs/renderengine/gl/GLSkiaShadowPort.h
@@ -17,13 +17,11 @@
#pragma once
#include <math/vec4.h>
+#include <renderengine/Mesh.h>
#include <ui/Rect.h>
namespace android {
namespace renderengine {
-
-class Mesh;
-
namespace gl {
/**
@@ -79,6 +77,20 @@
void fillIndicesForGeometry(const Geometry& shadowGeometry, int indexCount,
int startingVertexOffset, uint16_t* indices);
+/**
+ * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to
+ * darkness at that spot. Values are determined by an exponential falloff
+ * function provided by UX.
+ *
+ * The texture is used for quick lookup in theshadow shader.
+ *
+ * textureData - filled with shadow texture data that needs to be at least of
+ * size textureWidth
+ *
+ * textureWidth - width of the texture, height is always 1
+ */
+void fillShadowTextureData(uint8_t* textureData, size_t textureWidth);
+
} // namespace gl
} // namespace renderengine
} // namespace android
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index ba0e4ad..3ae35ec 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -550,7 +550,7 @@
String8 ProgramCache::generateVertexShader(const Key& needs) {
Formatter vs;
- if (needs.isTexturing()) {
+ if (needs.hasTextureCoords()) {
vs << "attribute vec4 texCoords;"
<< "varying vec2 outTexCoords;";
}
@@ -559,16 +559,16 @@
vs << "varying lowp vec2 outCropCoords;";
}
if (needs.drawShadows()) {
- vs << "attribute vec4 shadowColor;";
- vs << "varying vec4 outShadowColor;";
- vs << "attribute vec4 shadowParams;";
- vs << "varying vec3 outShadowParams;";
+ vs << "attribute lowp vec4 shadowColor;";
+ vs << "varying lowp vec4 outShadowColor;";
+ vs << "attribute lowp vec4 shadowParams;";
+ vs << "varying lowp vec3 outShadowParams;";
}
vs << "attribute vec4 position;"
<< "uniform mat4 projection;"
<< "uniform mat4 texture;"
<< "void main(void) {" << indent << "gl_Position = projection * position;";
- if (needs.isTexturing()) {
+ if (needs.hasTextureCoords()) {
vs << "outTexCoords = (texture * texCoords).st;";
}
if (needs.hasRoundedCorners()) {
@@ -592,11 +592,13 @@
fs << "precision mediump float;";
if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
- fs << "uniform samplerExternalOES sampler;"
- << "varying vec2 outTexCoords;";
+ fs << "uniform samplerExternalOES sampler;";
} else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
- fs << "uniform sampler2D sampler;"
- << "varying vec2 outTexCoords;";
+ fs << "uniform sampler2D sampler;";
+ }
+
+ if (needs.hasTextureCoords()) {
+ fs << "varying vec2 outTexCoords;";
}
if (needs.hasRoundedCorners()) {
@@ -625,19 +627,17 @@
if (needs.drawShadows()) {
fs << R"__SHADER__(
- varying vec4 outShadowColor;
- varying vec3 outShadowParams;
+ varying lowp vec4 outShadowColor;
+ varying lowp vec3 outShadowParams;
/**
* Returns the shadow color.
*/
vec4 getShadowColor()
{
- // exponential falloff function provided by UX
- float d = length(outShadowParams.xy);
- float distance = outShadowParams.z * (1.0 - d);
- float factor = 1.0 - clamp(distance, 0.0, 1.0);
- factor = exp(-factor * factor * 4.0) - 0.018;
+ lowp float d = length(outShadowParams.xy);
+ vec2 uv = vec2(outShadowParams.z * (1.0 - d), 0.5);
+ lowp float factor = texture2D(sampler, uv).a;
return outShadowColor * factor;
}
)__SHADER__";
diff --git a/libs/renderengine/gl/ProgramCache.h b/libs/renderengine/gl/ProgramCache.h
index c8b6da7..901e631 100644
--- a/libs/renderengine/gl/ProgramCache.h
+++ b/libs/renderengine/gl/ProgramCache.h
@@ -128,6 +128,7 @@
}
inline bool isTexturing() const { return (mKey & TEXTURE_MASK) != TEXTURE_OFF; }
+ inline bool hasTextureCoords() const { return isTexturing() && !drawShadows(); }
inline int getTextureTarget() const { return (mKey & TEXTURE_MASK); }
inline bool isPremultiplied() const { return (mKey & BLEND_MASK) == BLEND_PREMULT; }
inline bool isOpaque() const { return (mKey & OPACITY_MASK) == OPACITY_OPAQUE; }
diff --git a/libs/ui/include/ui/DisplayConfig.h b/libs/ui/include/ui/DisplayConfig.h
new file mode 100644
index 0000000..09b8211
--- /dev/null
+++ b/libs/ui/include/ui/DisplayConfig.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <type_traits>
+
+#include <ui/Size.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+// Configuration supported by physical display.
+struct DisplayConfig {
+ ui::Size resolution;
+ float xDpi = 0;
+ float yDpi = 0;
+
+ float refreshRate = 0;
+ nsecs_t appVsyncOffset = 0;
+ nsecs_t sfVsyncOffset = 0;
+ nsecs_t presentationDeadline = 0;
+};
+
+static_assert(std::is_trivially_copyable_v<DisplayConfig>);
+
+} // namespace android
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 38f8d6b..7773319 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,35 +14,18 @@
* limitations under the License.
*/
-#ifndef ANDROID_UI_DISPLAY_INFO_H
-#define ANDROID_UI_DISPLAY_INFO_H
+#pragma once
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <ui/Rotation.h>
-#include <utils/Timers.h>
+#include <type_traits>
namespace android {
-constexpr uint32_t NO_LAYER_STACK = static_cast<uint32_t>(-1);
-
+// Immutable information about physical display.
struct DisplayInfo {
- uint32_t w{0};
- uint32_t h{0};
- float xdpi{0};
- float ydpi{0};
- float fps{0};
- float density{0};
- ui::Rotation orientation{ui::ROTATION_0};
- bool secure{false};
- nsecs_t appVsyncOffset{0};
- nsecs_t presentationDeadline{0};
- uint32_t viewportW{0};
- uint32_t viewportH{0};
- uint32_t layerStack{NO_LAYER_STACK};
+ float density = 0.f;
+ bool secure = false;
};
-} // namespace android
+static_assert(std::is_trivially_copyable_v<DisplayInfo>);
-#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
+} // namespace android
diff --git a/libs/ui/include/ui/DisplayState.h b/libs/ui/include/ui/DisplayState.h
new file mode 100644
index 0000000..64efc84
--- /dev/null
+++ b/libs/ui/include/ui/DisplayState.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ui/Rotation.h>
+#include <ui/Size.h>
+
+#include <cstdint>
+#include <type_traits>
+
+namespace android::ui {
+
+using LayerStack = uint32_t;
+constexpr LayerStack NO_LAYER_STACK = static_cast<LayerStack>(-1);
+
+// Transactional state of physical or virtual display. Note that libgui defines
+// android::DisplayState as a superset of android::ui::DisplayState.
+struct DisplayState {
+ LayerStack layerStack = NO_LAYER_STACK;
+ Rotation orientation = ROTATION_0;
+ Size viewport;
+};
+
+static_assert(std::is_trivially_copyable_v<DisplayState>);
+
+} // namespace android::ui
diff --git a/libs/ui/include_vndk/ui/DisplayConfig.h b/libs/ui/include_vndk/ui/DisplayConfig.h
new file mode 120000
index 0000000..1450319
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayConfig.h
@@ -0,0 +1 @@
+../../include/ui/DisplayConfig.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayState.h b/libs/ui/include_vndk/ui/DisplayState.h
new file mode 120000
index 0000000..4e92849
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayState.h
@@ -0,0 +1 @@
+../../include/ui/DisplayState.h
\ No newline at end of file
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index 4dcc1ca..dfb9c92 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -16,10 +16,13 @@
#include <WindowSurface.h>
-#include <gui/SurfaceComposerClient.h>
+#include <utility>
+
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
-#include <ui/DisplayInfo.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
using namespace android;
@@ -33,28 +36,33 @@
return;
}
- // Get main display parameters.
- const auto mainDpy = SurfaceComposerClient::getInternalDisplayToken();
- if (mainDpy == nullptr) {
+ const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ if (displayToken == nullptr) {
fprintf(stderr, "ERROR: no display\n");
return;
}
- DisplayInfo mainDpyInfo;
- err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+ DisplayConfig displayConfig;
+ err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
if (err != NO_ERROR) {
- fprintf(stderr, "ERROR: unable to get display characteristics\n");
+ fprintf(stderr, "ERROR: unable to get active display config\n");
return;
}
- uint32_t width, height;
- if (mainDpyInfo.orientation != ui::ROTATION_0 && mainDpyInfo.orientation != ui::ROTATION_180) {
- // rotated
- width = mainDpyInfo.h;
- height = mainDpyInfo.w;
- } else {
- width = mainDpyInfo.w;
- height = mainDpyInfo.h;
+ ui::DisplayState displayState;
+ err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+ if (err != NO_ERROR) {
+ fprintf(stderr, "ERROR: unable to get display state\n");
+ return;
+ }
+
+ const ui::Size& resolution = displayConfig.resolution;
+ auto width = resolution.getWidth();
+ auto height = resolution.getHeight();
+
+ if (displayState.orientation == ui::ROTATION_90 ||
+ displayState.orientation == ui::ROTATION_270) {
+ std::swap(width, height);
}
sp<SurfaceControl> sc = surfaceComposerClient->createSurface(
diff --git a/services/automotive/display/CarWindowService.cpp b/services/automotive/display/CarWindowService.cpp
index e95c9e1..fbefef0 100644
--- a/services/automotive/display/CarWindowService.cpp
+++ b/services/automotive/display/CarWindowService.cpp
@@ -13,8 +13,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-#include <ui/DisplayInfo.h>
+
+#include <utility>
+
#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
#include "CarWindowService.h"
@@ -38,31 +42,37 @@
return nullptr;
}
- // Get main display parameters.
- sp<IBinder> mainDpy = SurfaceComposerClient::getInternalDisplayToken();
- if (mainDpy == nullptr) {
+ const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+ if (displayToken == nullptr) {
ALOGE("Failed to get internal display ");
return nullptr;
}
- DisplayInfo mainDpyInfo;
- err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo);
+
+ DisplayConfig displayConfig;
+ err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
if (err != NO_ERROR) {
- ALOGE("Failed to get display characteristics");
+ ALOGE("Failed to get active display config");
return nullptr;
}
- unsigned int mWidth, mHeight;
- if (mainDpyInfo.orientation != ui::ROTATION_0 &&
- mainDpyInfo.orientation != ui::ROTATION_180) {
- // rotated
- mWidth = mainDpyInfo.h;
- mHeight = mainDpyInfo.w;
- } else {
- mWidth = mainDpyInfo.w;
- mHeight = mainDpyInfo.h;
+
+ ui::DisplayState displayState;
+ err = SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+ if (err != NO_ERROR) {
+ ALOGE("Failed to get display state");
+ return nullptr;
+ }
+
+ const ui::Size& resolution = displayConfig.resolution;
+ auto width = resolution.getWidth();
+ auto height = resolution.getHeight();
+
+ if (displayState.orientation == ui::ROTATION_90 ||
+ displayState.orientation == ui::ROTATION_270) {
+ std::swap(width, height);
}
mSurfaceControl = mSurfaceComposerClient->createSurface(
- String8("Automotive Display"), mWidth, mHeight,
+ String8("Automotive Display"), width, height,
PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
if (mSurfaceControl == nullptr || !mSurfaceControl->isValid()) {
ALOGE("Failed to create SurfaceControl");
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index baba64f..6eed24a 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -20,6 +20,7 @@
"libbase",
"libbinder",
"libcutils",
+ "libgfxstats",
"libgraphicsenv",
"liblog",
"libutils",
@@ -52,7 +53,6 @@
name: "libgpuservice_sources",
srcs: [
"GpuService.cpp",
- "gpustats/GpuStats.cpp"
],
}
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index be4a462..91a76f1 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -24,14 +24,13 @@
#include <binder/Parcel.h>
#include <binder/PermissionCache.h>
#include <cutils/properties.h>
+#include <gpustats/GpuStats.h>
#include <private/android_filesystem_config.h>
#include <utils/String8.h>
#include <utils/Trace.h>
#include <vkjson.h>
-#include "gpustats/GpuStats.h"
-
namespace android {
using base::StringAppendF;
@@ -53,8 +52,9 @@
int64_t driverBuildTime, const std::string& appPackageName,
const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
bool isDriverLoaded, int64_t driverLoadingTime) {
- mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
- appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime);
+ mGpuStats->insertDriverStats(driverPackageName, driverVersionName, driverVersionCode,
+ driverBuildTime, appPackageName, vulkanVersion, driver,
+ isDriverLoaded, driverLoadingTime);
}
status_t GpuService::getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const {
diff --git a/services/gpuservice/TEST_MAPPING b/services/gpuservice/TEST_MAPPING
new file mode 100644
index 0000000..b345355
--- /dev/null
+++ b/services/gpuservice/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "gpuservice_unittest"
+ }
+ ]
+}
diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp
new file mode 100644
index 0000000..49a98cc
--- /dev/null
+++ b/services/gpuservice/gpustats/Android.bp
@@ -0,0 +1,21 @@
+cc_library_shared {
+ name: "libgfxstats",
+ srcs: [
+ "GpuStats.cpp",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libgraphicsenv",
+ "liblog",
+ "libutils",
+ ],
+ export_include_dirs: ["include"],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+}
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 7fff6ed..71e6b97 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "GpuStats"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include "GpuStats.h"
+#include <gpustats/GpuStats.h>
#include <cutils/properties.h>
#include <log/log.h>
@@ -74,10 +74,11 @@
}
}
-void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
- uint64_t driverVersionCode, int64_t driverBuildTime,
- const std::string& appPackageName, const int32_t vulkanVersion,
- GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) {
+void GpuStats::insertDriverStats(const std::string& driverPackageName,
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName,
+ const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
@@ -191,6 +192,11 @@
dumpAll = false;
}
+ if (dumpAll) {
+ dumpGlobalLocked(result);
+ dumpAppLocked(result);
+ }
+
if (argsSet.count("--clear")) {
bool clearAll = true;
@@ -208,13 +214,6 @@
mGlobalStats.clear();
mAppStats.clear();
}
-
- dumpAll = false;
- }
-
- if (dumpAll) {
- dumpGlobalLocked(result);
- dumpAppLocked(result);
}
}
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
similarity index 83%
rename from services/gpuservice/gpustats/GpuStats.h
rename to services/gpuservice/gpustats/include/gpustats/GpuStats.h
index 656b181..bcb9e0d 100644
--- a/services/gpuservice/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/include/gpustats/GpuStats.h
@@ -16,15 +16,15 @@
#pragma once
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/GraphicsEnv.h>
#include <utils/String16.h>
#include <utils/Vector.h>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
namespace android {
class GpuStats {
@@ -32,11 +32,12 @@
GpuStats() = default;
~GpuStats() = default;
- // Insert new gpu stats into global stats and app stats.
- void insert(const std::string& driverPackageName, const std::string& driverVersionName,
- uint64_t driverVersionCode, int64_t driverBuildTime,
- const std::string& appPackageName, const int32_t vulkanVersion,
- GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
+ // Insert new gpu driver stats into global stats and app stats.
+ void insertDriverStats(const std::string& driverPackageName,
+ const std::string& driverVersionName, uint64_t driverVersionCode,
+ int64_t driverBuildTime, const std::string& appPackageName,
+ const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
+ bool isDriverLoaded, int64_t driverLoadingTime);
// Insert target stats into app stats or potentially global stats as well.
void insertTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
const GpuStatsInfo::Stats stats, const uint64_t value);
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
new file mode 100644
index 0000000..fee5bd4
--- /dev/null
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -0,0 +1,34 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_test {
+ name: "gpuservice_unittest",
+ test_suites: ["device-tests"],
+ sanitize: {
+ address: true,
+ },
+ srcs: [
+ "GpuStatsTest.cpp",
+ ],
+ shared_libs: [
+ "libcutils",
+ "libgfxstats",
+ "libgraphicsenv",
+ "liblog",
+ "libutils",
+ ],
+ static_libs: [
+ "libgmock",
+ ],
+}
diff --git a/services/gpuservice/tests/unittests/AndroidTest.xml b/services/gpuservice/tests/unittests/AndroidTest.xml
new file mode 100644
index 0000000..66f51c7
--- /dev/null
+++ b/services/gpuservice/tests/unittests/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for gpuservice_unittest">
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="gpuservice_unittest->/data/local/tmp/gpuservice_unittest" />
+ </target_preparer>
+ <option name="test-suite-tag" value="apct" />
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="gpuservice_unittest" />
+ </test>
+</configuration>
diff --git a/services/gpuservice/tests/unittests/GpuStatsTest.cpp b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
new file mode 100644
index 0000000..276a334
--- /dev/null
+++ b/services/gpuservice/tests/unittests/GpuStatsTest.cpp
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "gpuservice_unittest"
+
+#include <cutils/properties.h>
+#include <gmock/gmock.h>
+#include <gpustats/GpuStats.h>
+#include <gtest/gtest.h>
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace {
+
+using testing::HasSubstr;
+
+// clang-format off
+#define BUILTIN_DRIVER_PKG_NAME "system"
+#define BUILTIN_DRIVER_VER_NAME "0"
+#define BUILTIN_DRIVER_VER_CODE 0
+#define BUILTIN_DRIVER_BUILD_TIME 123
+#define UPDATED_DRIVER_PKG_NAME "updated"
+#define UPDATED_DRIVER_VER_NAME "1"
+#define UPDATED_DRIVER_VER_CODE 1
+#define UPDATED_DRIVER_BUILD_TIME 234
+#define VULKAN_VERSION 345
+#define CPU_VULKAN_VERSION 456
+#define OPENGLES_VERSION 567
+#define APP_PKG_NAME_1 "testapp1"
+#define APP_PKG_NAME_2 "testapp2"
+#define DRIVER_LOADING_TIME_1 678
+#define DRIVER_LOADING_TIME_2 789
+#define DRIVER_LOADING_TIME_3 891
+
+enum InputCommand : int32_t {
+ DUMP_ALL = 0,
+ DUMP_GLOBAL = 1,
+ DUMP_APP = 2,
+ DUMP_ALL_THEN_CLEAR = 3,
+ DUMP_GLOBAL_THEN_CLEAR = 4,
+ DUMP_APP_THEN_CLEAR = 5,
+};
+// clang-format on
+
+class GpuStatsTest : public testing::Test {
+public:
+ GpuStatsTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ ~GpuStatsTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ std::string inputCommand(InputCommand cmd);
+
+ void SetUp() override {
+ property_set("ro.cpuvulkan.version", std::to_string(CPU_VULKAN_VERSION).c_str());
+ property_set("ro.opengles.version", std::to_string(OPENGLES_VERSION).c_str());
+ mCpuVulkanVersion = property_get_int32("ro.cpuvulkan.version", CPU_VULKAN_VERSION);
+ mGlesVersion = property_get_int32("ro.opengles.version", OPENGLES_VERSION);
+ }
+
+ std::unique_ptr<GpuStats> mGpuStats = std::make_unique<GpuStats>();
+ int32_t mCpuVulkanVersion = 0;
+ int32_t mGlesVersion = 0;
+};
+
+std::string GpuStatsTest::inputCommand(InputCommand cmd) {
+ std::string result;
+ Vector<String16> args;
+
+ switch (cmd) {
+ case InputCommand::DUMP_ALL:
+ break;
+ case InputCommand::DUMP_GLOBAL:
+ args.push_back(String16("--global"));
+ break;
+ case InputCommand::DUMP_APP:
+ args.push_back(String16("--app"));
+ break;
+ case InputCommand::DUMP_ALL_THEN_CLEAR:
+ args.push_back(String16("--clear"));
+ break;
+ case InputCommand::DUMP_GLOBAL_THEN_CLEAR:
+ args.push_back(String16("--global"));
+ args.push_back(String16("--clear"));
+ break;
+ case InputCommand::DUMP_APP_THEN_CLEAR:
+ args.push_back(String16("--app"));
+ args.push_back(String16("--clear"));
+ break;
+ }
+
+ mGpuStats->dump(args, &result);
+ return result;
+}
+
+TEST_F(GpuStatsTest, statsEmptyByDefault) {
+ ASSERT_TRUE(inputCommand(InputCommand::DUMP_ALL).empty());
+}
+
+TEST_F(GpuStatsTest, canInsertBuiltinDriverStats) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ std::string expectedResult = "driverPackageName = " + std::string(BUILTIN_DRIVER_PKG_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionName = " + std::string(BUILTIN_DRIVER_VER_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(BUILTIN_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverBuildTime = " + std::to_string(BUILTIN_DRIVER_BUILD_TIME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("glLoadingCount = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("glLoadingFailureCount = 0"));
+ expectedResult = "appPackageName = " + std::string(APP_PKG_NAME_1);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(BUILTIN_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "glDriverLoadingTime: " + std::to_string(DRIVER_LOADING_TIME_1);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canInsertUpdatedDriverStats) {
+ mGpuStats->insertDriverStats(UPDATED_DRIVER_PKG_NAME, UPDATED_DRIVER_VER_NAME,
+ UPDATED_DRIVER_VER_CODE, UPDATED_DRIVER_BUILD_TIME, APP_PKG_NAME_2,
+ VULKAN_VERSION, GpuStatsInfo::Driver::VULKAN_UPDATED, false,
+ DRIVER_LOADING_TIME_2);
+
+ std::string expectedResult = "driverPackageName = " + std::string(UPDATED_DRIVER_PKG_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionName = " + std::string(UPDATED_DRIVER_VER_NAME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(UPDATED_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "driverBuildTime = " + std::to_string(UPDATED_DRIVER_BUILD_TIME);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("vkLoadingCount = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("vkLoadingFailureCount = 1"));
+ expectedResult = "appPackageName = " + std::string(APP_PKG_NAME_2);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "driverVersionCode = " + std::to_string(UPDATED_DRIVER_VER_CODE);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+ expectedResult = "vkDriverLoadingTime: " + std::to_string(DRIVER_LOADING_TIME_2);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canInsertAngleDriverStats) {
+ mGpuStats->insertDriverStats(UPDATED_DRIVER_PKG_NAME, UPDATED_DRIVER_VER_NAME,
+ UPDATED_DRIVER_VER_CODE, UPDATED_DRIVER_BUILD_TIME, APP_PKG_NAME_2,
+ VULKAN_VERSION, GpuStatsInfo::Driver::ANGLE, true,
+ DRIVER_LOADING_TIME_3);
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("angleLoadingCount = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr("angleLoadingFailureCount = 0"));
+ std::string expectedResult = "angleDriverLoadingTime: " + std::to_string(DRIVER_LOADING_TIME_3);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canDump3dApiVersion) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ std::string expectedResult = "vulkanVersion = " + std::to_string(VULKAN_VERSION);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "cpuVulkanVersion = " + std::to_string(mCpuVulkanVersion);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+ expectedResult = "glesVersion = " + std::to_string(mGlesVersion);
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_GLOBAL), HasSubstr(expectedResult));
+}
+
+TEST_F(GpuStatsTest, canNotInsertTargetStatsBeforeProperSetup) {
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::CPU_VULKAN_IN_USE, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::FALSE_PREROTATION, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::GLES_1_IN_USE, 0);
+
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_APP).empty());
+}
+
+TEST_F(GpuStatsTest, canInsertTargetStatsAfterProperSetup) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::CPU_VULKAN_IN_USE, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::FALSE_PREROTATION, 0);
+ mGpuStats->insertTargetStats(APP_PKG_NAME_1, BUILTIN_DRIVER_VER_CODE,
+ GpuStatsInfo::Stats::GLES_1_IN_USE, 0);
+
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("cpuVulkanInUse = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("falsePrerotation = 1"));
+ EXPECT_THAT(inputCommand(InputCommand::DUMP_APP), HasSubstr("gles1InUse = 1"));
+}
+
+TEST_F(GpuStatsTest, canDumpAllBeforeClearAll) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_ALL_THEN_CLEAR).empty());
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_ALL).empty());
+}
+
+TEST_F(GpuStatsTest, canDumpGlobalBeforeClearGlobal) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL_THEN_CLEAR).empty());
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP).empty());
+}
+
+TEST_F(GpuStatsTest, canDumpAppBeforeClearApp) {
+ mGpuStats->insertDriverStats(BUILTIN_DRIVER_PKG_NAME, BUILTIN_DRIVER_VER_NAME,
+ BUILTIN_DRIVER_VER_CODE, BUILTIN_DRIVER_BUILD_TIME, APP_PKG_NAME_1,
+ VULKAN_VERSION, GpuStatsInfo::Driver::GL, true,
+ DRIVER_LOADING_TIME_1);
+
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_APP_THEN_CLEAR).empty());
+ EXPECT_TRUE(inputCommand(InputCommand::DUMP_APP).empty());
+ EXPECT_FALSE(inputCommand(InputCommand::DUMP_GLOBAL).empty());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index f6b5935..308e93a 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -83,6 +83,7 @@
srcs: [
"InputListener.cpp",
"InputReaderBase.cpp",
+ "InputThread.cpp",
],
shared_libs: [
diff --git a/services/inputflinger/InputThread.cpp b/services/inputflinger/InputThread.cpp
new file mode 100644
index 0000000..b87f7a1
--- /dev/null
+++ b/services/inputflinger/InputThread.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "InputThread.h"
+
+namespace android {
+
+namespace {
+
+// Implementation of Thread from libutils.
+class InputThreadImpl : public Thread {
+public:
+ explicit InputThreadImpl(std::function<void()> loop)
+ : Thread(/* canCallJava */ true), mThreadLoop(loop) {}
+
+ ~InputThreadImpl() {}
+
+private:
+ std::function<void()> mThreadLoop;
+
+ bool threadLoop() override {
+ mThreadLoop();
+ return true;
+ }
+};
+
+} // namespace
+
+InputThread::InputThread(std::string name, std::function<void()> loop, std::function<void()> wake)
+ : mName(name), mThreadWake(wake) {
+ mThread = new InputThreadImpl(loop);
+ mThread->run(mName.c_str(), ANDROID_PRIORITY_URGENT_DISPLAY);
+}
+
+InputThread::~InputThread() {
+ mThread->requestExit();
+ if (mThreadWake) {
+ mThreadWake();
+ }
+ mThread->requestExitAndWait();
+}
+
+bool InputThread::isCallingThread() {
+ return gettid() == mThread->getTid();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5ae2419..b2b5145 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -325,24 +325,6 @@
return dispatchEntry;
}
-// --- InputDispatcherThread ---
-
-class InputDispatcher::InputDispatcherThread : public Thread {
-public:
- explicit InputDispatcherThread(InputDispatcher* dispatcher)
- : Thread(/* canCallJava */ true), mDispatcher(dispatcher) {}
-
- ~InputDispatcherThread() {}
-
-private:
- InputDispatcher* mDispatcher;
-
- virtual bool threadLoop() override {
- mDispatcher->dispatchOnce();
- return true;
- }
-};
-
// --- InputDispatcher ---
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -367,8 +349,6 @@
mKeyRepeatState.lastKeyEntry = nullptr;
policy->getDispatcherConfiguration(&mConfig);
-
- mThread = new InputDispatcherThread(this);
}
InputDispatcher::~InputDispatcher() {
@@ -387,25 +367,21 @@
}
status_t InputDispatcher::start() {
- if (mThread->isRunning()) {
+ if (mThread) {
return ALREADY_EXISTS;
}
- return mThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
+ mThread = std::make_unique<InputThread>(
+ "InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });
+ return OK;
}
status_t InputDispatcher::stop() {
- if (!mThread->isRunning()) {
- return OK;
- }
- if (gettid() == mThread->getTid()) {
- ALOGE("InputDispatcher can only be stopped from outside of the InputDispatcherThread!");
+ if (mThread && mThread->isCallingThread()) {
+ ALOGE("InputDispatcher cannot be stopped from its own thread!");
return INVALID_OPERATION;
}
- // Directly calling requestExitAndWait() causes the thread to not exit
- // if mLooper is waiting for a long timeout.
- mThread->requestExit();
- mLooper->wake();
- return mThread->requestExitAndWait();
+ mThread.reset();
+ return OK;
}
void InputDispatcher::dispatchOnce() {
@@ -2424,26 +2400,28 @@
PointerCoords scaledCoords[MAX_POINTERS];
const PointerCoords* usingCoords = motionEntry->pointerCoords;
- // Set the X and Y offset depending on the input source.
- float xOffset, yOffset;
+ // Set the X and Y offset and X and Y scale depending on the input source.
+ float xOffset = 0.0f, yOffset = 0.0f;
+ float xScale = 1.0f, yScale = 1.0f;
if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&
!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
float globalScaleFactor = dispatchEntry->globalScaleFactor;
- float wxs = dispatchEntry->windowXScale;
- float wys = dispatchEntry->windowYScale;
- xOffset = dispatchEntry->xOffset * wxs;
- yOffset = dispatchEntry->yOffset * wys;
- if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) {
+ xScale = dispatchEntry->windowXScale;
+ yScale = dispatchEntry->windowYScale;
+ xOffset = dispatchEntry->xOffset * xScale;
+ yOffset = dispatchEntry->yOffset * yScale;
+ if (globalScaleFactor != 1.0f) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
scaledCoords[i] = motionEntry->pointerCoords[i];
- scaledCoords[i].scale(globalScaleFactor, wxs, wys);
+ // Don't apply window scale here since we don't want scale to affect raw
+ // coordinates. The scale will be sent back to the client and applied
+ // later when requesting relative coordinates.
+ scaledCoords[i].scale(globalScaleFactor, 1 /* windowXScale */,
+ 1 /* windowYScale */);
}
usingCoords = scaledCoords;
}
} else {
- xOffset = 0.0f;
- yOffset = 0.0f;
-
// We don't want the dispatch target to know.
if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
@@ -2462,10 +2440,8 @@
dispatchEntry->resolvedFlags,
motionEntry->edgeFlags, motionEntry->metaState,
motionEntry->buttonState,
- motionEntry->classification,
- dispatchEntry->windowXScale,
- dispatchEntry->windowYScale, xOffset, yOffset,
- motionEntry->xPrecision,
+ motionEntry->classification, xScale, yScale,
+ xOffset, yOffset, motionEntry->xPrecision,
motionEntry->yPrecision,
motionEntry->xCursorPosition,
motionEntry->yCursorPosition,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index a4ba0de..93de18d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -25,6 +25,7 @@
#include "InputDispatcherPolicyInterface.h"
#include "InputState.h"
#include "InputTarget.h"
+#include "InputThread.h"
#include "Monitor.h"
#include "TouchState.h"
#include "TouchedWindow.h"
@@ -124,8 +125,7 @@
STALE,
};
- class InputDispatcherThread;
- sp<InputDispatcherThread> mThread;
+ std::unique_ptr<InputThread> mThread;
sp<InputDispatcherPolicyInterface> mPolicy;
android::InputDispatcherConfiguration mConfig;
diff --git a/services/inputflinger/include/InputThread.h b/services/inputflinger/include/InputThread.h
new file mode 100644
index 0000000..407365a
--- /dev/null
+++ b/services/inputflinger/include/InputThread.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_THREAD_H
+#define _UI_INPUT_THREAD_H
+
+#include <utils/Thread.h>
+
+namespace android {
+
+/* A thread that loops continuously until destructed to process input events.
+ *
+ * Creating the InputThread starts it immediately. The thread begins looping the loop
+ * function until the InputThread is destroyed. The wake function is used to wake anything
+ * that sleeps in the loop when it is time for the thread to be destroyed.
+ */
+class InputThread {
+public:
+ explicit InputThread(std::string name, std::function<void()> loop,
+ std::function<void()> wake = nullptr);
+ virtual ~InputThread();
+
+ bool isCallingThread();
+
+private:
+ std::string mName;
+ std::function<void()> mThreadWake;
+ sp<Thread> mThread;
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_THREAD_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 05f0db1..2023c6e 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -49,25 +49,6 @@
namespace android {
-// --- InputReader::InputReaderThread ---
-
-/* Thread that reads raw events from the event hub and processes them, endlessly. */
-class InputReader::InputReaderThread : public Thread {
-public:
- explicit InputReaderThread(InputReader* reader)
- : Thread(/* canCallJava */ true), mReader(reader) {}
-
- ~InputReaderThread() {}
-
-private:
- InputReader* mReader;
-
- bool threadLoop() override {
- mReader->loopOnce();
- return true;
- }
-};
-
// --- InputReader ---
InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
@@ -83,7 +64,6 @@
mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
mQueuedListener = new QueuedInputListener(listener);
- mThread = new InputReaderThread(this);
{ // acquire lock
AutoMutex _l(mLock);
@@ -100,25 +80,21 @@
}
status_t InputReader::start() {
- if (mThread->isRunning()) {
+ if (mThread) {
return ALREADY_EXISTS;
}
- return mThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
+ mThread = std::make_unique<InputThread>(
+ "InputReader", [this]() { loopOnce(); }, [this]() { mEventHub->wake(); });
+ return OK;
}
status_t InputReader::stop() {
- if (!mThread->isRunning()) {
- return OK;
- }
- if (gettid() == mThread->getTid()) {
- ALOGE("InputReader can only be stopped from outside of the InputReaderThread!");
+ if (mThread && mThread->isCallingThread()) {
+ ALOGE("InputReader cannot be stopped from its own thread!");
return INVALID_OPERATION;
}
- // Directly calling requestExitAndWait() causes the thread to not exit
- // if mEventHub is waiting for a long timeout.
- mThread->requestExit();
- mEventHub->wake();
- return mThread->requestExitAndWait();
+ mThread.reset();
+ return OK;
}
void InputReader::loopOnce() {
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 5024906..02957cd 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -21,6 +21,7 @@
#include "InputListener.h"
#include "InputReaderBase.h"
#include "InputReaderContext.h"
+#include "InputThread.h"
#include <utils/Condition.h>
#include <utils/Mutex.h>
@@ -116,8 +117,7 @@
friend class ContextImpl;
private:
- class InputReaderThread;
- sp<InputReaderThread> mThread;
+ std::unique_ptr<InputThread> mThread;
Mutex mLock;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e85281d..61386f4 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -117,23 +117,24 @@
"relative to expectedPresent %" PRId64,
getDebugName(), addedTime, expectedPresentTime);
+ if (!isPlausible) {
+ mFlinger->mTimeStats->incrementBadDesiredPresent(getSequence());
+ }
+
const bool isDue = addedTime < expectedPresentTime;
return isDue || !isPlausible;
}
-bool BufferQueueLayer::setFrameRate(float frameRate) {
+bool BufferQueueLayer::setFrameRate(FrameRate frameRate) {
float oldFrameRate = 0.f;
status_t result = mConsumer->getFrameRate(&oldFrameRate);
- bool frameRateChanged = result < 0 || frameRate != oldFrameRate;
- mConsumer->setFrameRate(frameRate);
+ bool frameRateChanged = result < 0 || frameRate.rate != oldFrameRate;
+ mConsumer->setFrameRate(frameRate.rate);
return frameRateChanged;
}
-std::optional<float> BufferQueueLayer::getFrameRate() const {
- if (mLatchedFrameRate > 0.f || mLatchedFrameRate == FRAME_RATE_NO_VOTE)
- return mLatchedFrameRate;
-
- return {};
+Layer::FrameRate BufferQueueLayer::getFrameRate() const {
+ return FrameRate(mLatchedFrameRate, Layer::FrameRateCompatibility::Default);
}
// -----------------------------------------------------------------------
@@ -157,7 +158,14 @@
// able to be latched. To avoid this, grab this buffer anyway.
return true;
}
- return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ const bool fenceSignaled =
+ mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ if (!fenceSignaled) {
+ mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
+ TimeStats::LatchSkipReason::LateAcquire);
+ }
+
+ return fenceSignaled;
}
bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 2bd1e3d..598bc6b 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -56,8 +56,8 @@
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
- bool setFrameRate(float frameRate) override;
- std::optional<float> getFrameRate() const override;
+ bool setFrameRate(FrameRate frameRate) override;
+ FrameRate getFrameRate() const override;
// -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index c86c538..ed18901 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -98,6 +98,8 @@
}
}
+ mPreviousReleaseFence = releaseFence;
+
// Prevent tracing the same release multiple times.
if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
@@ -111,7 +113,7 @@
mTransformHint = orientation;
}
-void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
+void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
}
@@ -120,6 +122,16 @@
mDrawingState.callbackHandles);
mDrawingState.callbackHandles = {};
+
+ const sp<Fence>& releaseFence(mPreviousReleaseFence);
+ std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(releaseFence);
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (mPreviousFrameNumber != 0) {
+ mFrameEventHistory.addRelease(mPreviousFrameNumber, dequeueReadyTime,
+ std::move(releaseFenceTime));
+ }
+ }
}
bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
@@ -233,8 +245,21 @@
return true;
}
-bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime,
- nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) {
+bool BufferStateLayer::updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t desiredPresentTime) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mAcquireTimeline.updateSignalTimes();
+ std::shared_ptr<FenceTime> acquireFenceTime =
+ std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
+ NewFrameEventsEntry newTimestamps = {mCurrentState.frameNumber, postedTime, desiredPresentTime,
+ acquireFenceTime};
+ mFrameEventHistory.addQueue(newTimestamps);
+ return true;
+}
+
+bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
+ nsecs_t postTime, nsecs_t desiredPresentTime,
+ const client_cache_t& clientCacheId) {
if (mCurrentState.buffer) {
mReleasePreviousBuffer = true;
}
@@ -257,6 +282,7 @@
mFlinger->mScheduler->recordLayerHistory(this,
desiredPresentTime <= 0 ? 0 : desiredPresentTime);
+ updateFrameEventHistory(acquireFence, postTime, desiredPresentTime);
return true;
}
@@ -403,7 +429,14 @@
return true;
}
- return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
+ const bool fenceSignaled =
+ getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
+ if (!fenceSignaled) {
+ mFlinger->mTimeStats->incrementLatchSkipped(getSequence(),
+ TimeStats::LatchSkipReason::LateAcquire);
+ }
+
+ return fenceSignaled;
}
bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
@@ -546,10 +579,14 @@
return NO_ERROR;
}
-status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
+status_t BufferStateLayer::updateFrameNumber(nsecs_t latchTime) {
// TODO(marissaw): support frame history events
mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mDrawingState.frameNumber;
+ {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mFrameEventHistory.addLatch(mCurrentFrameNumber, latchTime);
+ }
return NO_ERROR;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 9427283..03d9684 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -68,8 +68,8 @@
bool setTransformToDisplayInverse(bool transformToDisplayInverse) override;
bool setCrop(const Rect& crop) override;
bool setFrame(const Rect& frame) override;
- bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, nsecs_t desiredPresentTime,
- const client_cache_t& clientCacheId) override;
+ bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime,
+ nsecs_t desiredPresentTime, const client_cache_t& clientCacheId) override;
bool setAcquireFence(const sp<Fence>& fence) override;
bool setDataspace(ui::Dataspace dataspace) override;
bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -109,6 +109,9 @@
void gatherBufferInfo() override;
private:
+ bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t requestedPresentTime);
+
uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 04854d0..dbdfd5b 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -61,7 +61,7 @@
}
bool ColorLayer::isVisible() const {
- return !isHiddenByPolicy() && getAlpha() > 0.0f;
+ return !isHiddenByPolicy() && getAlpha() > 0.0_hf;
}
bool ColorLayer::setColor(const half3& color) {
@@ -104,7 +104,9 @@
}
bool ColorLayer::isOpaque(const Layer::State& s) const {
- return (s.flags & layer_state_t::eLayerOpaque) != 0;
+ // Consider the layer to be opaque if its opaque flag is set or its effective
+ // alpha (considering the alpha of its parents as well) is 1.0;
+ return (s.flags & layer_state_t::eLayerOpaque) != 0 || getAlpha() == 1.0_hf;
}
ui::Dataspace ColorLayer::getDataSpace() const {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index a5da0b1..4ab7082 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -163,7 +163,8 @@
// Sets the projection state to use
virtual void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
- const Rect& viewport, const Rect& scissor, bool needsFiltering) = 0;
+ const Rect& viewport, const Rect& sourceClip,
+ const Rect& destinationClip, bool needsFiltering) = 0;
// Sets the bounds to use
virtual void setBounds(const ui::Size&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index f469e62..8dc440c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -39,7 +39,8 @@
std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
void setProjection(const ui::Transform&, uint32_t orientation, const Rect& frame,
- const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
+ const Rect& viewport, const Rect& sourceClip, const Rect& destinationClip,
+ bool needsFiltering) override;
void setBounds(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index e700b76..66ed2b6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -79,8 +79,11 @@
// The logical space user viewport rectangle
Rect viewport;
- // The physical space scissor rectangle
- Rect scissor;
+ // The physical space source clip rectangle
+ Rect sourceClip;
+
+ // The physical space destination clip rectangle
+ Rect destinationClip;
// If true, RenderEngine filtering should be enabled
bool needsFiltering{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index c41302d..59906b9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -37,8 +37,9 @@
MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>());
MOCK_METHOD1(setCompositionEnabled, void(bool));
- MOCK_METHOD6(setProjection,
- void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&, bool));
+ MOCK_METHOD7(setProjection,
+ void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&,
+ const Rect&, bool));
MOCK_METHOD1(setBounds, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index f12d1c7..ce4b84a 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -107,11 +107,13 @@
}
void Output::setProjection(const ui::Transform& transform, uint32_t orientation, const Rect& frame,
- const Rect& viewport, const Rect& scissor, bool needsFiltering) {
+ const Rect& viewport, const Rect& sourceClip,
+ const Rect& destinationClip, bool needsFiltering) {
auto& outputState = editState();
outputState.transform = transform;
outputState.orientation = orientation;
- outputState.scissor = scissor;
+ outputState.sourceClip = sourceClip;
+ outputState.destinationClip = destinationClip;
outputState.frame = frame;
outputState.viewport = viewport;
outputState.needsFiltering = needsFiltering;
@@ -834,8 +836,8 @@
const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
renderengine::DisplaySettings clientCompositionDisplay;
- clientCompositionDisplay.physicalDisplay = outputState.scissor;
- clientCompositionDisplay.clip = outputState.scissor;
+ clientCompositionDisplay.physicalDisplay = outputState.destinationClip;
+ clientCompositionDisplay.clip = outputState.sourceClip;
clientCompositionDisplay.globalTransform = outputState.transform.asMatrix4();
clientCompositionDisplay.orientation = outputState.orientation;
clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 84d79f7..ca5be48 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -40,7 +40,8 @@
dumpVal(out, "frame", frame);
dumpVal(out, "viewport", viewport);
- dumpVal(out, "scissor", scissor);
+ dumpVal(out, "sourceClip", sourceClip);
+ dumpVal(out, "destinationClip", destinationClip);
dumpVal(out, "needsFiltering", needsFiltering);
out.append("\n ");
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6e8d3df..463d095 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -249,16 +249,19 @@
const int32_t orientation = 123;
const Rect frame{1, 2, 3, 4};
const Rect viewport{5, 6, 7, 8};
- const Rect scissor{9, 10, 11, 12};
+ const Rect sourceClip{9, 10, 11, 12};
+ const Rect destinationClip{13, 14, 15, 16};
const bool needsFiltering = true;
- mOutput->setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
+ mOutput->setProjection(transform, orientation, frame, viewport, sourceClip, destinationClip,
+ needsFiltering);
EXPECT_THAT(mOutput->getState().transform, transform);
EXPECT_EQ(orientation, mOutput->getState().orientation);
EXPECT_EQ(frame, mOutput->getState().frame);
EXPECT_EQ(viewport, mOutput->getState().viewport);
- EXPECT_EQ(scissor, mOutput->getState().scissor);
+ EXPECT_EQ(sourceClip, mOutput->getState().sourceClip);
+ EXPECT_EQ(destinationClip, mOutput->getState().destinationClip);
EXPECT_EQ(needsFiltering, mOutput->getState().needsFiltering);
}
@@ -2778,7 +2781,8 @@
mOutput.mState.frame = kDefaultOutputFrame;
mOutput.mState.viewport = kDefaultOutputViewport;
- mOutput.mState.scissor = kDefaultOutputScissor;
+ mOutput.mState.sourceClip = kDefaultOutputSourceClip;
+ mOutput.mState.destinationClip = kDefaultOutputDestinationClip;
mOutput.mState.transform = ui::Transform{kDefaultOutputOrientation};
mOutput.mState.orientation = kDefaultOutputOrientation;
mOutput.mState.dataspace = kDefaultOutputDataspace;
@@ -2822,7 +2826,8 @@
static const Rect kDefaultOutputFrame;
static const Rect kDefaultOutputViewport;
- static const Rect kDefaultOutputScissor;
+ static const Rect kDefaultOutputSourceClip;
+ static const Rect kDefaultOutputDestinationClip;
static const mat4 kDefaultColorTransformMat;
static const Region kDebugRegion;
@@ -2842,7 +2847,8 @@
const Rect OutputComposeSurfacesTest::kDefaultOutputFrame{1001, 1002, 1003, 1004};
const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008};
-const Rect OutputComposeSurfacesTest::kDefaultOutputScissor{1009, 1010, 1011, 1012};
+const Rect OutputComposeSurfacesTest::kDefaultOutputSourceClip{1009, 1010, 1011, 1012};
+const Rect OutputComposeSurfacesTest::kDefaultOutputDestinationClip{1013, 1014, 1015, 1016};
const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5f};
const Region OutputComposeSurfacesTest::kDebugRegion{Rect{100, 101, 102, 103}};
const HdrCapabilities OutputComposeSurfacesTest::
@@ -3085,9 +3091,10 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(true)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(),
- kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
+ mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
+ mat4(), Region::INVALID_REGION,
+ kDefaultOutputOrientation})
.execute()
.expectAFenceWasReturned();
}
@@ -3096,9 +3103,10 @@
verify().ifMixedCompositionIs(true)
.andIfUsesHdr(false)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(),
- kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
+ mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
+ mat4(), Region::INVALID_REGION,
+ kDefaultOutputOrientation})
.execute()
.expectAFenceWasReturned();
}
@@ -3107,8 +3115,8 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(),
- kDefaultMaxLuminance, kDefaultOutputDataspace,
+ .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
+ mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
kDefaultOutputOrientation})
.execute()
@@ -3119,8 +3127,8 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(false)
.andIfSkipColorTransform(false)
- .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(),
- kDefaultMaxLuminance, kDefaultOutputDataspace,
+ .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
+ mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
kDefaultOutputOrientation})
.execute()
@@ -3132,9 +3140,10 @@
verify().ifMixedCompositionIs(false)
.andIfUsesHdr(true)
.andIfSkipColorTransform(true)
- .thenExpectDisplaySettingsUsed({kDefaultOutputScissor, kDefaultOutputScissor, mat4(),
- kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ .thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputSourceClip,
+ mat4(), kDefaultMaxLuminance, kDefaultOutputDataspace,
+ mat4(), Region::INVALID_REGION,
+ kDefaultOutputOrientation})
.execute()
.expectAFenceWasReturned();
}
@@ -3345,7 +3354,8 @@
GenerateClientCompositionRequestsTest_ThreeLayers() {
mOutput.mState.frame = kDisplayFrame;
mOutput.mState.viewport = kDisplayViewport;
- mOutput.mState.scissor = kDisplayScissor;
+ mOutput.mState.sourceClip = kDisplaySourceClip;
+ mOutput.mState.destinationClip = kDisplayDestinationClip;
mOutput.mState.transform = ui::Transform{kDisplayOrientation};
mOutput.mState.orientation = kDisplayOrientation;
mOutput.mState.needsFiltering = false;
@@ -3376,14 +3386,17 @@
static const Rect kDisplayFrame;
static const Rect kDisplayViewport;
- static const Rect kDisplayScissor;
+ static const Rect kDisplaySourceClip;
+ static const Rect kDisplayDestinationClip;
std::array<Layer, 3> mLayers;
};
const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayFrame(0, 0, 100, 200);
const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayViewport(0, 0, 101, 201);
-const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayScissor(0, 0, 102, 202);
+const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplaySourceClip(0, 0, 102, 202);
+const Rect GenerateClientCompositionRequestsTest_ThreeLayers::kDisplayDestinationClip(0, 0, 103,
+ 203);
TEST_F(GenerateClientCompositionRequestsTest_ThreeLayers, handlesNoClientCompostionLayers) {
EXPECT_CALL(mLayers[0].mOutputLayer, requiresClientComposition()).WillOnce(Return(false));
@@ -3789,13 +3802,15 @@
const Rect kPortraitFrame(0, 0, 1000, 2000);
const Rect kPortraitViewport(0, 0, 2000, 1000);
- const Rect kPortraitScissor(0, 0, 1000, 2000);
+ const Rect kPortraitSourceClip(0, 0, 1000, 2000);
+ const Rect kPortraitDestinationClip(0, 0, 1000, 2000);
const uint32_t kPortraitOrientation = TR_ROT_90;
constexpr ui::Dataspace kOutputDataspace = ui::Dataspace::DISPLAY_P3;
mOutput.mState.frame = kPortraitFrame;
mOutput.mState.viewport = kPortraitViewport;
- mOutput.mState.scissor = kPortraitScissor;
+ mOutput.mState.sourceClip = kPortraitSourceClip;
+ mOutput.mState.destinationClip = kPortraitDestinationClip;
mOutput.mState.transform = ui::Transform{kPortraitOrientation};
mOutput.mState.orientation = kPortraitOrientation;
mOutput.mState.needsFiltering = false;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 4ae6dad..6ff39b4 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -146,12 +146,12 @@
return mCompositionDisplay->getState().dataspace;
}
-void DisplayDevice::setLayerStack(uint32_t stack) {
+void DisplayDevice::setLayerStack(ui::LayerStack stack) {
mCompositionDisplay->setLayerStackFilter(stack, isPrimary());
}
-void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
- mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
+void DisplayDevice::setDisplaySize(int width, int height) {
+ mCompositionDisplay->setBounds(ui::Size(width, height));
}
void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect frame) {
@@ -222,10 +222,13 @@
const bool needsFiltering =
(!globalTransform.preserveRects() || (type >= ui::Transform::SCALE));
- Rect scissor = globalTransform.transform(viewport);
- if (scissor.isEmpty()) {
- scissor = displayBounds;
+ Rect sourceClip = globalTransform.transform(viewport);
+ if (sourceClip.isEmpty()) {
+ sourceClip = displayBounds;
}
+ // For normal display use we always set the source and destination clip
+ // rectangles to the same values.
+ const Rect& destinationClip = sourceClip;
uint32_t transformOrientation;
@@ -236,8 +239,8 @@
transformOrientation = ui::Transform::toRotationFlags(orientation);
}
- getCompositionDisplay()->setProjection(globalTransform, transformOrientation,
- frame, viewport, scissor, needsFiltering);
+ getCompositionDisplay()->setProjection(globalTransform, transformOrientation, frame, viewport,
+ sourceClip, destinationClip, needsFiltering);
}
ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
@@ -286,7 +289,7 @@
return mCompositionDisplay->getState().needsFiltering;
}
-uint32_t DisplayDevice::getLayerStack() const {
+ui::LayerStack DisplayDevice::getLayerStack() const {
return mCompositionDisplay->getState().layerStackId;
}
@@ -302,8 +305,8 @@
return mCompositionDisplay->getState().frame;
}
-const Rect& DisplayDevice::getScissor() const {
- return mCompositionDisplay->getState().scissor;
+const Rect& DisplayDevice::getSourceClip() const {
+ return mCompositionDisplay->getState().sourceClip;
}
bool DisplayDevice::hasWideColorGamut() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index ff48ecd..f45feae 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -16,8 +16,6 @@
#pragma once
-#include <stdlib.h>
-
#include <memory>
#include <optional>
#include <string>
@@ -30,7 +28,7 @@
#include <math/mat4.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayState.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -80,12 +78,12 @@
// secure surfaces.
bool isSecure() const;
- int getWidth() const;
- int getHeight() const;
+ int getWidth() const;
+ int getHeight() const;
+ ui::Size getSize() const { return {getWidth(), getHeight()}; }
- void setLayerStack(uint32_t stack);
- void setDisplaySize(const int newWidth, const int newHeight);
-
+ void setLayerStack(ui::LayerStack);
+ void setDisplaySize(int width, int height);
void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
@@ -96,9 +94,9 @@
const ui::Transform& getTransform() const;
const Rect& getViewport() const;
const Rect& getFrame() const;
- const Rect& getScissor() const;
+ const Rect& getSourceClip() const;
bool needsFiltering() const;
- uint32_t getLayerStack() const;
+ ui::LayerStack getLayerStack() const;
const std::optional<DisplayId>& getId() const;
const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
@@ -185,7 +183,7 @@
int32_t sequenceId = sNextSequenceId++;
std::optional<DisplayId> displayId;
sp<IGraphicBufferProducer> surface;
- uint32_t layerStack = NO_LAYER_STACK;
+ ui::LayerStack layerStack = ui::NO_LAYER_STACK;
Rect viewport;
Rect frame;
ui::Rotation orientation = ui::ROTATION_0;
@@ -271,7 +269,7 @@
Rect getSourceCrop() const override {
// use the projected display viewport by default.
if (mSourceCrop.isEmpty()) {
- return mDisplay->getScissor();
+ return mDisplay->getSourceClip();
}
// Recompute the device transformation for the source crop.
@@ -280,14 +278,14 @@
ui::Transform translateLogical;
ui::Transform scale;
const Rect& viewport = mDisplay->getViewport();
- const Rect& scissor = mDisplay->getScissor();
+ const Rect& sourceClip = mDisplay->getSourceClip();
const Rect& frame = mDisplay->getFrame();
const auto flags = ui::Transform::toRotationFlags(mDisplay->getPhysicalOrientation());
rotation.set(flags, getWidth(), getHeight());
translateLogical.set(-viewport.left, -viewport.top);
- translatePhysical.set(scissor.left, scissor.top);
+ translatePhysical.set(sourceClip.left, sourceClip.top);
scale.set(frame.getWidth() / float(viewport.getWidth()), 0, 0,
frame.getHeight() / float(viewport.getHeight()));
const ui::Transform finalTransform =
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 50c88f2..cf1e8b0 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -117,7 +117,6 @@
mCurrentState.frameRateSelectionPriority = PRIORITY_UNSET;
mCurrentState.metadata = args.metadata;
mCurrentState.shadowRadius = 0.f;
- mCurrentState.frameRate = 0.f;
// drawing state & current state are identical
mDrawingState = mCurrentState;
@@ -1245,7 +1244,7 @@
return true;
}
-bool Layer::setFrameRate(float frameRate) {
+bool Layer::setFrameRate(FrameRate frameRate) {
if (mCurrentState.frameRate == frameRate) {
return false;
}
@@ -1257,11 +1256,8 @@
return true;
}
-std::optional<float> Layer::getFrameRate() const {
- const auto frameRate = getDrawingState().frameRate;
- if (frameRate > 0.f || frameRate == FRAME_RATE_NO_VOTE) return frameRate;
-
- return {};
+Layer::FrameRate Layer::getFrameRate() const {
+ return getDrawingState().frameRate;
}
void Layer::deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber) {
@@ -1804,6 +1800,15 @@
}
}
+void Layer::traverse(LayerVector::StateSet state, const LayerVector::Visitor& visitor) {
+ visitor(this);
+ const LayerVector& children =
+ state == LayerVector::StateSet::Drawing ? mDrawingChildren : mCurrentChildren;
+ for (const sp<Layer>& child : children) {
+ child->traverse(state, visitor);
+ }
+}
+
LayerVector Layer::makeChildrenTraversalList(LayerVector::StateSet stateSet,
const std::vector<Layer*>& layersInTree) {
LOG_ALWAYS_FATAL_IF(stateSet == LayerVector::StateSet::Invalid,
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 24e1d25..f7907c3 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -136,6 +136,34 @@
float radius = 0.0f;
};
+ // FrameRateCompatibility specifies how we should interpret the frame rate associated with
+ // the layer.
+ enum class FrameRateCompatibility {
+ Default, // Layer didn't specify any specific handling strategy
+
+ ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the
+ // content properly. Any other value will result in a pull down.
+
+ NoVote, // Layer doesn't have any requirements for the refresh rate and
+ // should not be considered when the display refresh rate is determined.
+ };
+
+ // Encapsulates the frame rate and compatibility of the layer. This information will be used
+ // when the display refresh rate is determined.
+ struct FrameRate {
+ float rate;
+ FrameRateCompatibility type;
+
+ FrameRate() : rate(0), type(FrameRateCompatibility::Default) {}
+ FrameRate(float rate, FrameRateCompatibility type) : rate(rate), type(type) {}
+
+ bool operator==(const FrameRate& other) const {
+ return rate == other.rate && type == other.type;
+ }
+
+ bool operator!=(const FrameRate& other) const { return !(*this == other); }
+ };
+
struct State {
Geometry active_legacy;
Geometry requested_legacy;
@@ -227,7 +255,7 @@
// Priority of the layer assigned by Window Manager.
int32_t frameRateSelectionPriority;
- float frameRate;
+ FrameRate frameRate;
};
explicit Layer(const LayerCreationArgs& args);
@@ -329,8 +357,8 @@
virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; };
virtual bool setCrop(const Rect& /*crop*/) { return false; };
virtual bool setFrame(const Rect& /*frame*/) { return false; };
- virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, nsecs_t /*postTime*/,
- nsecs_t /*desiredPresentTime*/,
+ virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, const sp<Fence>& /*acquireFence*/,
+ nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
const client_cache_t& /*clientCacheId*/) {
return false;
};
@@ -679,6 +707,15 @@
renderengine::ShadowSettings getShadowSettings(const Rect& viewport) const;
+ /**
+ * Traverse this layer and it's hierarchy of children directly. Unlike traverseInZOrder
+ * which will not emit children who have relativeZOrder to another layer, this method
+ * just directly emits all children. It also emits them in no particular order.
+ * So this method is not suitable for graphical operations, as it doesn't represent
+ * the scene state, but it's also more efficient than traverseInZOrder and so useful for
+ * book-keeping.
+ */
+ void traverse(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
void traverseInReverseZOrder(LayerVector::StateSet stateSet,
const LayerVector::Visitor& visitor);
void traverseInZOrder(LayerVector::StateSet stateSet, const LayerVector::Visitor& visitor);
@@ -745,9 +782,8 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
- constexpr static auto FRAME_RATE_NO_VOTE = -1.0f;
- virtual bool setFrameRate(float frameRate);
- virtual std::optional<float> getFrameRate() const;
+ virtual bool setFrameRate(FrameRate frameRate);
+ virtual FrameRate getFrameRate() const;
protected:
// constant
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 7c959b9..9b94920 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -86,6 +86,14 @@
layer->traverseInReverseZOrder(stateSet, visitor);
}
}
+
+void LayerVector::traverse(const Visitor& visitor) const {
+ for (auto i = static_cast<int64_t>(size()) - 1; i >= 0; i--) {
+ const auto& layer = (*this)[i];
+ layer->traverse(mStateSet, visitor);
+ }
+}
+
} // namespace android
// TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/LayerVector.h b/services/surfaceflinger/LayerVector.h
index 88d7711..a531f4f 100644
--- a/services/surfaceflinger/LayerVector.h
+++ b/services/surfaceflinger/LayerVector.h
@@ -50,7 +50,7 @@
using Visitor = std::function<void(Layer*)>;
void traverseInReverseZOrder(StateSet stateSet, const Visitor& visitor) const;
void traverseInZOrder(StateSet stateSet, const Visitor& visitor) const;
-
+ void traverse(const Visitor& visitor) const;
private:
const StateSet mStateSet;
};
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index d3d9d3a..682679c 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -155,7 +155,7 @@
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setFrameRate(Layer::FRAME_RATE_NO_VOTE);
+ mLayer->setFrameRate(Layer::FrameRate(0, Layer::FrameRateCompatibility::NoVote));
// setting Layer's Z requires resorting layersSortedByZ
ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
@@ -208,7 +208,7 @@
const int32_t buttom = top + display->getHeight() / 32;
auto buffer = mBufferCache[refreshRate.fps];
- mLayer->setBuffer(buffer, 0, 0, {});
+ mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, {});
mLayer->setFrame(Rect(left, top, right, buttom));
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index b976523..9aada11 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -39,7 +39,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
- if (layer.getFrameRate().has_value()) {
+ if (layer.getFrameRate().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -126,18 +126,27 @@
// Only use the layer if the reference still exists.
if (layer || CC_UNLIKELY(mTraceEnabled)) {
// Check if frame rate was set on layer.
- auto frameRate = layer->getFrameRate();
- if (frameRate.has_value() && frameRate.value() > 0.f) {
- summary.push_back(
- {layer->getName(), LayerVoteType::Explicit, *frameRate, /* weight */ 1.0f});
+ const auto frameRate = layer->getFrameRate();
+ if (frameRate.rate > 0.f) {
+ const auto voteType = [&]() {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return LayerVoteType::ExplicitDefault;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return LayerVoteType::ExplicitExactOrMultiple;
+ case Layer::FrameRateCompatibility::NoVote:
+ return LayerVoteType::NoVote;
+ }
+ }();
+ summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f});
} else if (recent) {
- frameRate = info->getRefreshRate(now);
- summary.push_back({layer->getName(), LayerVoteType::Heuristic, *frameRate,
+ summary.push_back({layer->getName(), LayerVoteType::Heuristic,
+ info->getRefreshRate(now),
/* weight */ 1.0f});
}
if (CC_UNLIKELY(mTraceEnabled)) {
- trace(weakLayer, round<int>(*frameRate));
+ trace(weakLayer, round<int>(frameRate.rate));
}
}
}
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index a6d2c74..ce085f4 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -40,7 +40,7 @@
namespace {
bool isLayerActive(const Layer& layer, const LayerInfoV2& info, nsecs_t threshold) {
- if (layer.getFrameRate().has_value()) {
+ if (layer.getFrameRate().rate > 0) {
return layer.isVisible();
}
return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
@@ -63,13 +63,17 @@
const auto& name = layer->getName();
const auto noVoteTag = "LFPS NoVote " + name;
const auto heuristicVoteTag = "LFPS Heuristic " + name;
- const auto explicitVoteTag = "LFPS Explicit " + name;
+ const auto explicitDefaultVoteTag = "LFPS ExplicitDefault" + name;
+ const auto explicitExactOrMultipleVoteTag = "LFPS ExplicitExactOrMultiple" + name;
const auto minVoteTag = "LFPS Min " + name;
const auto maxVoteTag = "LFPS Max " + name;
ATRACE_INT(noVoteTag.c_str(), type == LayerHistory::LayerVoteType::NoVote ? 1 : 0);
ATRACE_INT(heuristicVoteTag.c_str(), type == LayerHistory::LayerVoteType::Heuristic ? fps : 0);
- ATRACE_INT(explicitVoteTag.c_str(), type == LayerHistory::LayerVoteType::Explicit ? fps : 0);
+ ATRACE_INT(explicitDefaultVoteTag.c_str(),
+ type == LayerHistory::LayerVoteType::ExplicitDefault ? fps : 0);
+ ATRACE_INT(explicitExactOrMultipleVoteTag.c_str(),
+ type == LayerHistory::LayerVoteType::ExplicitExactOrMultiple ? fps : 0);
ATRACE_INT(minVoteTag.c_str(), type == LayerHistory::LayerVoteType::Min ? 1 : 0);
ATRACE_INT(maxVoteTag.c_str(), type == LayerHistory::LayerVoteType::Max ? 1 : 0);
@@ -160,12 +164,18 @@
i++;
// Set layer vote if set
const auto frameRate = layer->getFrameRate();
- if (frameRate.has_value()) {
- if (*frameRate == Layer::FRAME_RATE_NO_VOTE) {
- info->setLayerVote(LayerVoteType::NoVote, 0.f);
- } else {
- info->setLayerVote(LayerVoteType::Explicit, *frameRate);
+ const auto voteType = [&]() {
+ switch (frameRate.type) {
+ case Layer::FrameRateCompatibility::Default:
+ return LayerVoteType::ExplicitDefault;
+ case Layer::FrameRateCompatibility::ExactOrMultiple:
+ return LayerVoteType::ExplicitExactOrMultiple;
+ case Layer::FrameRateCompatibility::NoVote:
+ return LayerVoteType::NoVote;
}
+ }();
+ if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) {
+ info->setLayerVote(voteType, frameRate.rate);
} else {
info->resetLayerVote();
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index d94d758..345b8f9 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -54,8 +54,15 @@
return mFrameTimes.back().queueTime >= getActiveLayerThreshold(now);
}
+bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const {
+ return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>(
+ mFrameTimeValidSince.time_since_epoch())
+ .count();
+}
+
bool LayerInfoV2::isFrequent(nsecs_t now) const {
- // Assume layer is infrequent if too few present times have been recorded.
+ // If we know nothing about this layer we consider it as frequent as it might be the start
+ // of an animation.
if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
return true;
}
@@ -63,12 +70,24 @@
// Layer is frequent if the earliest value in the window of most recent present times is
// within threshold.
const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE;
+ if (!isFrameTimeValid(*it)) {
+ return true;
+ }
+
const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count();
return it->queueTime >= threshold;
}
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
// The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates
+ if (mFrameTimes.size() < 2) {
+ return false;
+ }
+
+ if (!isFrameTimeValid(mFrameTimes.front())) {
+ return false;
+ }
+
if (mFrameTimes.size() < HISTORY_SIZE &&
mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
return false;
@@ -100,8 +119,7 @@
static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
// Now once we calculated the refresh rate we need to make sure that all the frames we captured
- // are evenly distrubuted and we don't calculate the average across some burst of frames.
-
+ // are evenly distributed and we don't calculate the average across some burst of frames.
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
const nsecs_t presentTimeDeltas =
std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index 564f05e..90f6310 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -82,12 +82,25 @@
// updated time, the updated time is the present time.
nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
- void clearHistory() { mFrameTimes.clear(); }
+ void clearHistory() {
+ // Mark mFrameTimeValidSince to now to ignore all previous frame times.
+ // We are not deleting the old frame to keep track of whether we should treat the first
+ // buffer as Max as we don't know anything about this layer or Min as this layer is
+ // posting infrequent updates.
+ mFrameTimeValidSince = std::chrono::steady_clock::now();
+ }
private:
+ // Used to store the layer timestamps
+ struct FrameTimeData {
+ nsecs_t presetTime; // desiredPresentTime, if provided
+ nsecs_t queueTime; // buffer queue time
+ };
+
bool isFrequent(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
std::optional<float> calculateRefreshRateIfPossible();
+ bool isFrameTimeValid(const FrameTimeData&) const;
// Used for sanitizing the heuristic data
const nsecs_t mHighRefreshRatePeriod;
@@ -103,12 +116,9 @@
float fps;
} mLayerVote;
- // Used to store the layer timestamps
- struct FrameTimeData {
- nsecs_t presetTime; // desiredPresentTime, if provided
- nsecs_t queueTime; // buffer queue time
- };
std::deque<FrameTimeData> mFrameTimes;
+ std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince =
+ std::chrono::steady_clock::now();
static constexpr size_t HISTORY_SIZE = 90;
static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
};
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index c187049..c73e825 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -37,7 +37,8 @@
int explicitContentFramerate = 0;
for (const auto& layer : layers) {
const auto desiredRefreshRateRound = round<int>(layer.desiredRefreshRate);
- if (layer.vote == LayerVoteType::Explicit) {
+ if (layer.vote == LayerVoteType::ExplicitDefault ||
+ layer.vote == LayerVoteType::ExplicitExactOrMultiple) {
if (desiredRefreshRateRound > explicitContentFramerate) {
explicitContentFramerate = desiredRefreshRateRound;
}
@@ -94,7 +95,8 @@
int noVoteLayers = 0;
int minVoteLayers = 0;
int maxVoteLayers = 0;
- int explicitVoteLayers = 0;
+ int explicitDefaultVoteLayers = 0;
+ int explicitExactOrMultipleVoteLayers = 0;
for (const auto& layer : layers) {
if (layer.vote == LayerVoteType::NoVote)
noVoteLayers++;
@@ -102,8 +104,10 @@
minVoteLayers++;
else if (layer.vote == LayerVoteType::Max)
maxVoteLayers++;
- else if (layer.vote == LayerVoteType::Explicit)
- explicitVoteLayers++;
+ else if (layer.vote == LayerVoteType::ExplicitDefault)
+ explicitDefaultVoteLayers++;
+ else if (layer.vote == LayerVoteType::ExplicitExactOrMultiple)
+ explicitExactOrMultipleVoteLayers++;
}
// Only if all layers want Min we should return Min
@@ -112,7 +116,7 @@
}
// If we have some Max layers and no Explicit we should return Max
- if (maxVoteLayers > 0 && explicitVoteLayers == 0) {
+ if (maxVoteLayers > 0 && explicitDefaultVoteLayers + explicitExactOrMultipleVoteLayers == 0) {
return *mAvailableRefreshRates.back();
}
@@ -125,14 +129,28 @@
}
for (const auto& layer : layers) {
+ ALOGV("Calculating score for %s (type: %d)", layer.name.c_str(), layer.vote);
if (layer.vote == LayerVoteType::NoVote || layer.vote == LayerVoteType::Min ||
layer.vote == LayerVoteType::Max) {
continue;
}
- // If we have Explicit layers, ignore the Huristic ones
- if (explicitVoteLayers > 0 && layer.vote == LayerVoteType::Heuristic) {
- continue;
+ // Adjust the weight in case we have explicit layers. The priority is:
+ // - ExplicitExactOrMultiple
+ // - ExplicitDefault
+ // - Heuristic
+ auto weight = layer.weight;
+ if (explicitExactOrMultipleVoteLayers + explicitDefaultVoteLayers > 0) {
+ if (layer.vote == LayerVoteType::Heuristic) {
+ weight /= 2.f;
+ }
+ }
+
+ if (explicitExactOrMultipleVoteLayers > 0) {
+ if (layer.vote == LayerVoteType::Heuristic ||
+ layer.vote == LayerVoteType::ExplicitDefault) {
+ weight /= 2.f;
+ }
}
for (auto& [refreshRate, overallScore] : scores) {
@@ -148,28 +166,30 @@
}
float layerScore;
+ static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
if (displayFramesRem == 0) {
// Layer desired refresh rate matches the display rate.
- layerScore = layer.weight * 1.0f;
+ layerScore = weight * 1.0f;
} else if (displayFramesQuot == 0) {
// Layer desired refresh rate is higher the display rate.
- layerScore = layer.weight * layerPeriod / displayPeriod;
+ layerScore = weight *
+ (static_cast<float>(layerPeriod) / static_cast<float>(displayPeriod)) *
+ (1.0f / (MAX_FRAMES_TO_FIT + 1));
} else {
// Layer desired refresh rate is lower the display rate. Check how well it fits the
// cadence
auto diff = std::abs(displayFramesRem - (displayPeriod - displayFramesRem));
int iter = 2;
- static constexpr size_t MAX_ITERATOR = 10; // Stop calculating when score < 0.1
- while (diff > MARGIN && iter < MAX_ITERATOR) {
+ while (diff > MARGIN && iter < MAX_FRAMES_TO_FIT) {
diff = diff - (displayPeriod - diff);
iter++;
}
- layerScore = layer.weight * 1.0f / iter;
+ layerScore = weight * (1.0f / iter);
}
- ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
- layer.weight, 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
+ ALOGV("%s (weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), weight,
+ 1e9f / layerPeriod, refreshRate->name.c_str(), layerScore);
overallScore += layerScore;
}
}
@@ -196,20 +216,12 @@
const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- if (!mRefreshRateSwitching) {
- return *mCurrentRefreshRate;
- } else {
- return *mAvailableRefreshRates.front();
- }
+ return *mAvailableRefreshRates.front();
}
const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const {
std::lock_guard lock(mLock);
- if (!mRefreshRateSwitching) {
- return *mCurrentRefreshRate;
- } else {
return *mAvailableRefreshRates.back();
- }
}
const RefreshRate& RefreshRateConfigs::getCurrentRefreshRate() const {
@@ -222,18 +234,14 @@
mCurrentRefreshRate = &mRefreshRates.at(configId);
}
-RefreshRateConfigs::RefreshRateConfigs(bool refreshRateSwitching,
- const std::vector<InputConfig>& configs,
- HwcConfigIndexType currentHwcConfig)
- : mRefreshRateSwitching(refreshRateSwitching) {
+RefreshRateConfigs::RefreshRateConfigs(const std::vector<InputConfig>& configs,
+ HwcConfigIndexType currentHwcConfig) {
init(configs, currentHwcConfig);
}
RefreshRateConfigs::RefreshRateConfigs(
- bool refreshRateSwitching,
const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
- HwcConfigIndexType currentConfigId)
- : mRefreshRateSwitching(refreshRateSwitching) {
+ HwcConfigIndexType currentConfigId) {
std::vector<InputConfig> inputConfigs;
for (size_t configId = 0; configId < configs.size(); ++configId) {
auto configGroup = HwcConfigGroupType(configs[configId]->getConfigGroup());
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 80d42cc..fc95959 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -94,16 +94,16 @@
// Returns true if config is allowed by the current policy.
bool isConfigAllowed(HwcConfigIndexType config) const EXCLUDES(mLock);
- // Returns true if this device is doing refresh rate switching. This won't change at runtime.
- bool refreshRateSwitchingSupported() const { return mRefreshRateSwitching; }
-
// Describes the different options the layer voted for refresh rate
enum class LayerVoteType {
- NoVote, // Doesn't care about the refresh rate
- Min, // Minimal refresh rate available
- Max, // Maximal refresh rate available
- Heuristic, // Specific refresh rate that was calculated by platform using a heuristic
- Explicit, // Specific refresh rate that was provided by the app
+ NoVote, // Doesn't care about the refresh rate
+ Min, // Minimal refresh rate available
+ Max, // Maximal refresh rate available
+ Heuristic, // Specific refresh rate that was calculated by platform using a heuristic
+ ExplicitDefault, // Specific refresh rate that was provided by the app with Default
+ // compatibility
+ ExplicitExactOrMultiple // Specific refresh rate that was provided by the app with
+ // ExactOrMultiple compatibility
};
// Captures the layer requirements for a refresh rate. This will be used to determine the
@@ -164,10 +164,9 @@
nsecs_t vsyncPeriod = 0;
};
- RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
+ RefreshRateConfigs(const std::vector<InputConfig>& configs,
HwcConfigIndexType currentHwcConfig);
- RefreshRateConfigs(bool refreshRateSwitching,
- const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
HwcConfigIndexType currentConfigId);
private:
@@ -205,8 +204,6 @@
const RefreshRate* mMinSupportedRefreshRate;
const RefreshRate* mMaxSupportedRefreshRate;
- const bool mRefreshRateSwitching;
-
mutable std::mutex mLock;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 5868463..56d1581 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -408,7 +408,8 @@
"SurfaceView - "
"com.google.android.youtube/"
"com.google.android.apps.youtube.app.WatchWhileActivity#0") {
- layer->setFrameRate(vote);
+ layer->setFrameRate(
+ Layer::FrameRate(vote, Layer::FrameRateCompatibility::ExactOrMultiple));
}
}
}
@@ -529,8 +530,6 @@
using base::StringAppendF;
const char* const states[] = {"off", "on"};
- const bool supported = mRefreshRateConfigs.refreshRateSwitchingSupported();
- StringAppendF(&result, "+ Refresh rate switching: %s\n", states[supported]);
StringAppendF(&result, "+ Content detection: %s\n", states[mLayerHistory != nullptr]);
StringAppendF(&result, "+ Idle timer: %s\n",
@@ -564,7 +563,8 @@
bool Scheduler::layerHistoryHasClientSpecifiedFrameRate() {
for (const auto& layer : mFeatures.contentRequirements) {
- if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::Explicit) {
+ if (layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitDefault ||
+ layer.vote == scheduler::RefreshRateConfigs::LayerVoteType::ExplicitExactOrMultiple) {
return true;
}
}
@@ -573,35 +573,44 @@
}
HwcConfigIndexType Scheduler::calculateRefreshRateType() {
- if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
- return mRefreshRateConfigs.getCurrentRefreshRate().configId;
+ // This block of the code checks whether any layers used the SetFrameRate API. If they have,
+ // their request should be honored regardless of whether the device has refresh rate switching
+ // turned off.
+ if (layerHistoryHasClientSpecifiedFrameRate()) {
+ if (!mUseContentDetectionV2) {
+ return mRefreshRateConfigs.getRefreshRateForContent(mFeatures.contentRequirements)
+ .configId;
+ } else {
+ return mRefreshRateConfigs.getRefreshRateForContentV2(mFeatures.contentRequirements)
+ .configId;
+ }
}
// If the layer history doesn't have the frame rate specified, use the old path. NOTE:
// if we remove the kernel idle timer, and use our internal idle timer, this code will have to
// be refactored.
- if (!layerHistoryHasClientSpecifiedFrameRate()) {
- // If Display Power is not in normal operation we want to be in performance mode.
- // When coming back to normal mode, a grace period is given with DisplayPowerTimer
- if (!mFeatures.isDisplayPowerStateNormal ||
- mFeatures.displayPowerTimer == TimerState::Reset) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ // If Display Power is not in normal operation we want to be in performance mode.
+ // When coming back to normal mode, a grace period is given with DisplayPowerTimer
+ if (mDisplayPowerTimer &&
+ (!mFeatures.isDisplayPowerStateNormal ||
+ mFeatures.displayPowerTimer == TimerState::Reset)) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
- // As long as touch is active we want to be in performance mode
- if (mFeatures.touch == TouchState::Active) {
- return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
- }
+ // As long as touch is active we want to be in performance mode
+ if (mTouchTimer && mFeatures.touch == TouchState::Active) {
+ return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
+ }
- // If timer has expired as it means there is no new content on the screen
- if (mFeatures.idleTimer == TimerState::Expired) {
- return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
- }
+ // If timer has expired as it means there is no new content on the screen
+ if (mIdleTimer && mFeatures.idleTimer == TimerState::Expired) {
+ return mRefreshRateConfigs.getMinRefreshRateByPolicy().configId;
}
if (!mUseContentDetectionV2) {
- // If content detection is off we choose performance as we don't know the content fps
+ // If content detection is off we choose performance as we don't know the content fps.
if (mFeatures.contentDetection == ContentDetectionState::Off) {
+ // TODO(b/148428554): Be careful to not always call this.
return mRefreshRateConfigs.getMaxRefreshRateByPolicy().configId;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 62d47e1..e4578f8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -61,8 +61,10 @@
#include <renderengine/RenderEngine.h>
#include <ui/ColorSpace.h>
#include <ui/DebugUtils.h>
+#include <ui/DisplayConfig.h>
#include <ui/DisplayInfo.h>
#include <ui/DisplayStatInfo.h>
+#include <ui/DisplayState.h>
#include <ui/GraphicBufferAllocator.h>
#include <ui/PixelFormat.h>
#include <ui/UiConfig.h>
@@ -115,6 +117,7 @@
#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
+#include <android/configuration.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/types.h>
@@ -182,6 +185,19 @@
bool mLocked;
};
+// TODO(b/141333600): Consolidate with HWC2::Display::Config::Builder::getDefaultDensity.
+constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV / 160.f;
+
+float getDensityFromProperty(const char* property, bool required) {
+ char value[PROPERTY_VALUE_MAX];
+ const float density = property_get(property, value, nullptr) > 0 ? std::atof(value) : 0.f;
+ if (!density && required) {
+ ALOGE("%s must be defined as a build property", property);
+ return FALLBACK_DENSITY;
+ }
+ return density / 160.f;
+}
+
// Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
bool validateCompositionDataspace(Dataspace dataspace) {
return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
@@ -249,7 +265,8 @@
mFrameTracer(std::make_unique<FrameTracer>()),
mEventQueue(mFactory.createMessageQueue()),
mCompositionEngine(mFactory.createCompositionEngine()),
- mPendingSyncInputWindows(false) {}
+ mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)),
+ mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
@@ -538,12 +555,6 @@
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
- // set the refresh rate according to the policy
- const auto& performanceRefreshRate = mRefreshRateConfigs->getMaxRefreshRateByPolicy();
- changeRefreshRateLocked(performanceRefreshRate, Scheduler::ConfigEvent::None);
- }
-
if (property_get_bool("sf.debug.show_refresh_rate_overlay", false)) {
mRefreshRateOverlay = std::make_unique<RefreshRateOverlay>(*this);
mRefreshRateOverlay->changeRefreshRate(mRefreshRateConfigs->getCurrentRefreshRate());
@@ -734,8 +745,56 @@
return NO_ERROR;
}
+status_t SurfaceFlinger::getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState* state) {
+ if (!displayToken || !state) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ state->layerStack = display->getLayerStack();
+ state->orientation = display->getOrientation();
+
+ const Rect viewport = display->getViewport();
+ state->viewport = viewport.isValid() ? viewport.getSize() : display->getSize();
+
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo* info) {
+ if (!displayToken || !info) {
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock lock(mStateLock);
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ if (!display) {
+ return NAME_NOT_FOUND;
+ }
+
+ if (display->isVirtual()) {
+ return INVALID_OPERATION;
+ }
+
+ if (mEmulatedDisplayDensity) {
+ info->density = mEmulatedDisplayDensity;
+ } else {
+ info->density = display->isPrimary() ? mInternalDisplayDensity : FALLBACK_DENSITY;
+ }
+
+ info->secure = display->isSecure();
+
+ return NO_ERROR;
+}
+
status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
- Vector<DisplayInfo>* configs) {
+ Vector<DisplayConfig>* configs) {
if (!displayToken || !configs) {
return BAD_VALUE;
}
@@ -747,78 +806,42 @@
return NAME_NOT_FOUND;
}
- // TODO: Not sure if display density should handled by SF any longer
- class Density {
- static float getDensityFromProperty(char const* propName) {
- char property[PROPERTY_VALUE_MAX];
- float density = 0.0f;
- if (property_get(propName, property, nullptr) > 0) {
- density = strtof(property, nullptr);
- }
- return density;
- }
- public:
- static float getEmuDensity() {
- return getDensityFromProperty("qemu.sf.lcd_density"); }
- static float getBuildDensity() {
- return getDensityFromProperty("ro.sf.lcd_density"); }
- };
+ const bool isInternal = (displayId == getInternalDisplayIdLocked());
configs->clear();
for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
- DisplayInfo info = DisplayInfo();
+ DisplayConfig config;
- float xdpi = hwConfig->getDpiX();
- float ydpi = hwConfig->getDpiY();
+ auto width = hwConfig->getWidth();
+ auto height = hwConfig->getHeight();
- info.w = hwConfig->getWidth();
- info.h = hwConfig->getHeight();
- // Default display viewport to display width and height
- info.viewportW = info.w;
- info.viewportH = info.h;
+ auto xDpi = hwConfig->getDpiX();
+ auto yDpi = hwConfig->getDpiY();
- if (displayId == getInternalDisplayIdLocked()) {
- // The density of the device is provided by a build property
- float density = Density::getBuildDensity() / 160.0f;
- if (density == 0) {
- // the build doesn't provide a density -- this is wrong!
- // use xdpi instead
- ALOGE("ro.sf.lcd_density must be defined as a build property");
- density = xdpi / 160.0f;
- }
- if (Density::getEmuDensity()) {
- // if "qemu.sf.lcd_density" is specified, it overrides everything
- xdpi = ydpi = density = Density::getEmuDensity();
- density /= 160.0f;
- }
- info.density = density;
-
- const auto display = getDefaultDisplayDeviceLocked();
- info.orientation = display->getOrientation();
-
- // This is for screenrecord
- const Rect viewport = display->getViewport();
- if (viewport.isValid()) {
- info.viewportW = uint32_t(viewport.getWidth());
- info.viewportH = uint32_t(viewport.getHeight());
- }
- info.layerStack = display->getLayerStack();
- } else {
- // TODO: where should this value come from?
- static const int TV_DENSITY = 213;
- info.density = TV_DENSITY / 160.0f;
-
- const auto display = getDisplayDeviceLocked(displayToken);
- info.layerStack = display->getLayerStack();
+ if (isInternal &&
+ (internalDisplayOrientation == ui::ROTATION_90 ||
+ internalDisplayOrientation == ui::ROTATION_270)) {
+ std::swap(width, height);
+ std::swap(xDpi, yDpi);
}
- info.xdpi = xdpi;
- info.ydpi = ydpi;
- info.fps = 1e9 / hwConfig->getVsyncPeriod();
+ config.resolution = ui::Size(width, height);
- const auto offset = mPhaseConfiguration->getOffsetsForRefreshRate(info.fps);
- info.appVsyncOffset = offset.late.app;
+ if (mEmulatedDisplayDensity) {
+ config.xDpi = mEmulatedDisplayDensity;
+ config.yDpi = mEmulatedDisplayDensity;
+ } else {
+ config.xDpi = xDpi;
+ config.yDpi = yDpi;
+ }
+
+ const nsecs_t period = hwConfig->getVsyncPeriod();
+ config.refreshRate = 1e9f / period;
+
+ const auto offsets = mPhaseConfiguration->getOffsetsForRefreshRate(config.refreshRate);
+ config.appVsyncOffset = offsets.late.app;
+ config.sfVsyncOffset = offsets.late.sf;
// This is how far in advance a buffer must be queued for
// presentation at a given time. If you want a buffer to appear
@@ -832,18 +855,9 @@
//
// We add an additional 1ms to allow for processing time and
// differences between the ideal and actual refresh rate.
- info.presentationDeadline = hwConfig->getVsyncPeriod() - offset.late.sf + 1000000;
+ config.presentationDeadline = period - config.sfVsyncOffset + 1000000;
- // All non-virtual displays are currently considered secure.
- info.secure = true;
-
- if (displayId == getInternalDisplayIdLocked() &&
- (internalDisplayOrientation == ui::ROTATION_90 ||
- internalDisplayOrientation == ui::ROTATION_270)) {
- std::swap(info.w, info.h);
- }
-
- configs->push_back(info);
+ configs->push_back(config);
}
return NO_ERROR;
@@ -2059,7 +2073,7 @@
compositorTiming = getBE().mCompositorTiming;
}
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
bool frameLatched = layer->onPostComposition(displayDevice, glCompositionDoneFenceTime,
presentFenceTime, compositorTiming);
if (frameLatched) {
@@ -2496,7 +2510,7 @@
const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Notify all layers of available frames
- mCurrentState.traverseInZOrder([expectedPresentTime](Layer* layer) {
+ mCurrentState.traverse([expectedPresentTime](Layer* layer) {
layer->notifyAvailableFrames(expectedPresentTime);
});
@@ -2506,7 +2520,7 @@
*/
if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
@@ -2553,7 +2567,7 @@
sp<const DisplayDevice> hintDisplay;
uint32_t currentlayerStack = 0;
bool first = true;
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
@@ -2699,8 +2713,7 @@
auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId));
mRefreshRateConfigs =
- std::make_unique<scheduler::RefreshRateConfigs>(refresh_rate_switching(false),
- getHwComposer().getConfigs(
+ std::make_unique<scheduler::RefreshRateConfigs>(getHwComposer().getConfigs(
primaryDisplayId),
currentConfig);
mRefreshRateStats =
@@ -2781,7 +2794,7 @@
// clear the "changed" flags in current state
mCurrentState.colorMatrixChanged = false;
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
layer->commitChildList();
// If the layer can be reached when traversing mDrawingState, then the layer is no
@@ -2792,7 +2805,7 @@
});
commitOffscreenLayers();
- mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateMirrorInfo(); });
+ mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
}
void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) {
@@ -2817,7 +2830,7 @@
void SurfaceFlinger::commitOffscreenLayers() {
for (Layer* offscreenLayer : mOffscreenLayers) {
- offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [](Layer* layer) {
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing, [](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
@@ -2858,7 +2871,7 @@
// 3.) Layer 1 is latched.
// Display is now waiting on Layer 1's frame, which is behind layer 0's
// second frame. But layer 0's second frame could be waiting on display.
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
if (layer->shouldPresentNow(expectedPresentTime)) {
@@ -2876,7 +2889,7 @@
// be shown on screen. Therefore, we need to latch and release buffers of offscreen
// layers to ensure dequeueBuffer doesn't block indefinitely.
for (Layer* offscreenLayer : mOffscreenLayers) {
- offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing,
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing,
[&](Layer* l) { l->latchAndReleaseBuffer(); });
}
@@ -2911,7 +2924,7 @@
mBootStage = BootStage::BOOTANIMATION;
}
- mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+ mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
// Only continue with the refresh if there is actually new work to do
return !mLayersWithQueuedFrames.empty() && newDataLatched;
@@ -3535,7 +3548,9 @@
}
}
if (what & layer_state_t::eFrameRateChanged) {
- if (layer->setFrameRate(s.frameRate)) flags |= eTraversalNeeded;
+ if (layer->setFrameRate(
+ Layer::FrameRate(s.frameRate, Layer::FrameRateCompatibility::Default)))
+ flags |= eTraversalNeeded;
}
// This has to happen after we reparent children because when we reparent to null we remove
// child layers from current state and remove its relative z. If the children are reparented in
@@ -3577,7 +3592,8 @@
buffer = s.buffer;
}
if (buffer) {
- if (layer->setBuffer(buffer, postTime, desiredPresentTime, s.cachedBuffer)) {
+ if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime,
+ s.cachedBuffer)) {
flags |= eTraversalNeeded;
}
}
@@ -3733,7 +3749,7 @@
bool matchFound = true;
while (matchFound) {
matchFound = false;
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
if (layer->getName() == uniqueName) {
matchFound = true;
uniqueName = base::StringPrintf("%s#%u", name, ++dupeCounter);
@@ -4104,7 +4120,7 @@
const bool clearAll = args.size() < 2;
const auto name = clearAll ? String8() : String8(args[1]);
- mCurrentState.traverseInZOrder([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) {
if (clearAll || layer->getName() == name.string()) {
layer->clearFrameStats();
}
@@ -4120,7 +4136,7 @@
// This should only be called from the main thread. Otherwise it would need
// the lock and should use mCurrentState rather than mDrawingState.
void SurfaceFlinger::logFrameStats() {
- mDrawingState.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverse([&](Layer* layer) {
layer->logFrameStats();
});
@@ -4355,7 +4371,7 @@
result.append("Offscreen Layers:\n");
postMessageSync(new LambdaMessage([&]() {
for (Layer* offscreenLayer : mOffscreenLayers) {
- offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ offscreenLayer->traverse(LayerVector::StateSet::Drawing, [&](Layer* layer) {
layer->dumpCallingUidPid(result);
});
}
@@ -4614,7 +4630,9 @@
case GET_PHYSICAL_DISPLAY_TOKEN:
case GET_DISPLAY_COLOR_MODES:
case GET_DISPLAY_NATIVE_PRIMARIES:
+ case GET_DISPLAY_INFO:
case GET_DISPLAY_CONFIGS:
+ case GET_DISPLAY_STATE:
case GET_DISPLAY_STATS:
case GET_SUPPORTED_FRAME_TIMESTAMPS:
// Calling setTransactionState is safe, because you need to have been
@@ -4644,12 +4662,6 @@
}
return OK;
}
- // The following codes are deprecated and should never be allowed to access SF.
- case CONNECT_DISPLAY_UNUSED:
- case CREATE_GRAPHIC_BUFFER_ALLOC_UNUSED: {
- ALOGE("Attempting to access SurfaceFlinger with unused code: %u", code);
- return PERMISSION_DENIED;
- }
case CAPTURE_SCREEN_BY_ID: {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
@@ -5588,6 +5600,10 @@
// ---------------------------------------------------------------------------
+void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const {
+ layersSortedByZ.traverse(visitor);
+}
+
void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const {
layersSortedByZ.traverseInZOrder(stateSet, visitor);
}
@@ -5677,26 +5693,19 @@
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig(), vsyncPeriod);
- if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
- auto configId = mScheduler->getPreferredConfigId();
- auto preferredRefreshRate = configId
- ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
- : mRefreshRateConfigs->getMinRefreshRateByPolicy();
- ALOGV("trying to switch to Scheduler preferred config %d (%s)",
- preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str());
- if (isDisplayConfigAllowed(preferredRefreshRate.configId)) {
- ALOGV("switching to Scheduler preferred config %d",
- preferredRefreshRate.configId.value());
- setDesiredActiveConfig(
- {preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed});
- } else {
- // Set the highest allowed config
- setDesiredActiveConfig({mRefreshRateConfigs->getMaxRefreshRateByPolicy().configId,
- Scheduler::ConfigEvent::Changed});
- }
+ auto configId = mScheduler->getPreferredConfigId();
+ auto preferredRefreshRate = configId
+ ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
+ // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
+ : mRefreshRateConfigs->getRefreshRateFromConfigId(defaultConfig);
+ ALOGV("trying to switch to Scheduler preferred config %d (%s)",
+ preferredRefreshRate.configId.value(), preferredRefreshRate.name.c_str());
+
+ if (isDisplayConfigAllowed(preferredRefreshRate.configId)) {
+ ALOGV("switching to Scheduler preferred config %d", preferredRefreshRate.configId.value());
+ setDesiredActiveConfig({preferredRefreshRate.configId, Scheduler::ConfigEvent::Changed});
} else {
- ALOGV("switching to config %d", defaultConfig.value());
- setDesiredActiveConfig({defaultConfig, Scheduler::ConfigEvent::Changed});
+ LOG_ALWAYS_FATAL("Desired config not allowed: %d", preferredRefreshRate.configId.value());
}
return NO_ERROR;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f8980a5..ccf5794 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -384,6 +384,7 @@
renderengine::ShadowSettings globalShadowSettings;
+ void traverse(const LayerVector::Visitor& visitor) const;
void traverseInZOrder(const LayerVector::Visitor& visitor) const;
void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
};
@@ -433,13 +434,13 @@
float frameScale, bool childrenOnly) override;
status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
- status_t getDisplayConfigs(const sp<IBinder>& displayToken,
- Vector<DisplayInfo>* configs) override;
+ status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) override;
+ status_t getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo*) override;
+ status_t getDisplayConfigs(const sp<IBinder>& displayToken, Vector<DisplayConfig>*) override;
int getActiveConfig(const sp<IBinder>& displayToken) override;
- status_t getDisplayColorModes(const sp<IBinder>& displayToken,
- Vector<ui::ColorMode>* configs) override;
+ status_t getDisplayColorModes(const sp<IBinder>& displayToken, Vector<ui::ColorMode>*) override;
status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
- ui::DisplayPrimaries &primaries);
+ ui::DisplayPrimaries&) override;
ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken) override;
status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override;
status_t getAutoLowLatencyModeSupport(const sp<IBinder>& displayToken,
@@ -1164,6 +1165,9 @@
sp<RegionSamplingThread> mRegionSamplingThread;
ui::DisplayPrimaries mInternalDisplayPrimaries;
+ const float mInternalDisplayDensity;
+ const float mEmulatedDisplayDensity;
+
sp<IInputFlinger> mInputFlinger;
InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
// Should only be accessed by the main thread.
@@ -1180,7 +1184,7 @@
const sp<SetInputWindowsListener> mSetInputWindowsListener = new SetInputWindowsListener(this);
- bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
+ bool mPendingSyncInputWindows GUARDED_BY(mStateLock) = false;
Hwc2::impl::PowerAdvisor mPowerAdvisor;
// This should only be accessed on the main thread.
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index b4716eb..768074a 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -226,14 +226,6 @@
return static_cast<int64_t>(defaultValue);
}
-bool refresh_rate_switching(bool defaultValue) {
- auto temp = SurfaceFlingerProperties::refresh_rate_switching();
- if (temp.has_value()) {
- return *temp;
- }
- return defaultValue;
-}
-
int32_t set_idle_timer_ms(int32_t defaultValue) {
auto temp = SurfaceFlingerProperties::set_idle_timer_ms();
if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index e394cca..5f88322 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -73,8 +73,6 @@
int64_t color_space_agnostic_dataspace(
android::hardware::graphics::common::V1_2::Dataspace defaultValue);
-bool refresh_rate_switching(bool defaultValue);
-
int32_t set_idle_timer_ms(int32_t defaultValue);
int32_t set_touch_timer_ms(int32_t defaultValue);
diff --git a/services/surfaceflinger/TEST_MAPPING b/services/surfaceflinger/TEST_MAPPING
index eed975e..cab33ae 100644
--- a/services/surfaceflinger/TEST_MAPPING
+++ b/services/surfaceflinger/TEST_MAPPING
@@ -1,13 +1,7 @@
{
"presubmit": [
{
- "name": "libsurfaceflinger_unittest",
- // TODO(b/148517641): re-enable once this test is fixed
- "options": [
- {
- "exclude-filter": "FrameTracerTest.*"
- }
- ]
+ "name": "libsurfaceflinger_unittest"
},
{
"name": "libcompositionengine_test"
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 12c98da..fdf8a41 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -40,13 +40,18 @@
status_pull_atom_return_t TimeStats::pullAtomCallback(int32_t atom_tag,
pulled_stats_event_list* data, void* cookie) {
impl::TimeStats* timeStats = reinterpret_cast<impl::TimeStats*>(cookie);
+ status_pull_atom_return_t result = STATS_PULL_SKIP;
if (atom_tag == android::util::SURFACEFLINGER_STATS_GLOBAL_INFO) {
- return timeStats->populateGlobalAtom(data);
+ result = timeStats->populateGlobalAtom(data);
} else if (atom_tag == android::util::SURFACEFLINGER_STATS_LAYER_INFO) {
- return timeStats->populateLayerAtom(data);
+ result = timeStats->populateLayerAtom(data);
}
- return STATS_PULL_SKIP;
+ // Enable timestats now. The first full pull for a given build is expected to
+ // have empty or very little stats, as stats are first enabled after the
+ // first pull is completed for either the global or layer stats.
+ timeStats->enable();
+ return result;
}
status_pull_atom_return_t TimeStats::populateGlobalAtom(pulled_stats_event_list* data) {
@@ -167,13 +172,19 @@
}
}
+TimeStats::~TimeStats() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStatsDelegate->unregisterStatsPullAtomCallback(
+ android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
+ mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
+}
+
void TimeStats::onBootFinished() {
- // Temporarily enable TimeStats by default. Telemetry is disabled while
- // we move onto statsd, so TimeStats is currently not exercised at all
- // during testing without enabling by default.
- // TODO: remove this, as we should only be paying this overhead on devices
- // where statsd exists.
- enable();
+ std::lock_guard<std::mutex> lock(mMutex);
+ mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ TimeStats::pullAtomCallback, nullptr, this);
+ mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+ TimeStats::pullAtomCallback, nullptr, this);
}
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
@@ -352,7 +363,12 @@
TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
timeStatsLayer.totalFrames++;
timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
+ timeStatsLayer.lateAcquireFrames += layerRecord.lateAcquireFrames;
+ timeStatsLayer.badDesiredPresentFrames += layerRecord.badDesiredPresentFrames;
+
layerRecord.droppedFrames = 0;
+ layerRecord.lateAcquireFrames = 0;
+ layerRecord.badDesiredPresentFrames = 0;
const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
timeRecords[0].frameTime.acquireTime);
@@ -466,6 +482,36 @@
}
}
+void TimeStats::incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ ALOGV("[%d]-LatchSkipped-Reason[%d]", layerId,
+ static_cast<std::underlying_type<LatchSkipReason>::type>(reason));
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStatsTracker.count(layerId)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerId];
+
+ switch (reason) {
+ case LatchSkipReason::LateAcquire:
+ layerRecord.lateAcquireFrames++;
+ break;
+ }
+}
+
+void TimeStats::incrementBadDesiredPresent(int32_t layerId) {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+ ALOGV("[%d]-BadDesiredPresent", layerId);
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStatsTracker.count(layerId)) return;
+ LayerRecord& layerRecord = mTimeStatsTracker[layerId];
+ layerRecord.badDesiredPresentFrames++;
+}
+
void TimeStats::setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) {
if (!mEnabled.load()) return;
@@ -735,10 +781,6 @@
mEnabled.store(true);
mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
mPowerTime.prevTime = systemTime();
- mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- TimeStats::pullAtomCallback, nullptr, this);
- mStatsDelegate->registerStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
- TimeStats::pullAtomCallback, nullptr, this);
ALOGD("Enabled");
}
@@ -751,9 +793,6 @@
flushPowerTimeLocked();
mEnabled.store(false);
mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
- mStatsDelegate->unregisterStatsPullAtomCallback(
- android::util::SURFACEFLINGER_STATS_GLOBAL_INFO);
- mStatsDelegate->unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO);
ALOGD("Disabled");
}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 71f06af..7f58725 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -70,6 +70,18 @@
virtual void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
nsecs_t postTime) = 0;
virtual void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) = 0;
+ // Reasons why latching a particular buffer may be skipped
+ enum class LatchSkipReason {
+ // If the acquire fence did not fire on some devices we skip latching
+ // the buffer until the fence fires.
+ LateAcquire,
+ };
+ // Increments the counter of skipped latch buffers.
+ virtual void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) = 0;
+ // Increments the counter of bad desired present times for this layer.
+ // Bad desired present times are "implausible" and cause SurfaceFlinger to
+ // latch a buffer immediately to avoid stalling.
+ virtual void incrementBadDesiredPresent(int32_t layerId) = 0;
virtual void setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) = 0;
virtual void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) = 0;
virtual void setAcquireFence(int32_t layerId, uint64_t frameNumber,
@@ -116,6 +128,8 @@
// fences to signal, but rather waiting to receive those fences/timestamps.
int32_t waitData = -1;
uint32_t droppedFrames = 0;
+ uint32_t lateAcquireFrames = 0;
+ uint32_t badDesiredPresentFrames = 0;
TimeRecord prevTimeRecord;
std::deque<TimeRecord> timeRecords;
};
@@ -182,6 +196,8 @@
std::optional<size_t> maxPulledLayers,
std::optional<size_t> maxPulledHistogramBuckets);
+ ~TimeStats() override;
+
void onBootFinished() override;
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
@@ -200,6 +216,8 @@
void setPostTime(int32_t layerId, uint64_t frameNumber, const std::string& layerName,
nsecs_t postTime) override;
void setLatchTime(int32_t layerId, uint64_t frameNumber, nsecs_t latchTime) override;
+ void incrementLatchSkipped(int32_t layerId, LatchSkipReason reason) override;
+ void incrementBadDesiredPresent(int32_t layerId) override;
void setDesiredTime(int32_t layerId, uint64_t frameNumber, nsecs_t desiredTime) override;
void setAcquireTime(int32_t layerId, uint64_t frameNumber, nsecs_t acquireTime) override;
void setAcquireFence(int32_t layerId, uint64_t frameNumber,
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 0ba90e2..e2f85cc 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -83,6 +83,8 @@
StringAppendF(&result, "packageName = %s\n", packageName.c_str());
StringAppendF(&result, "totalFrames = %d\n", totalFrames);
StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
+ StringAppendF(&result, "lateAcquireFrames = %d\n", lateAcquireFrames);
+ StringAppendF(&result, "badDesiredPresentFrames = %d\n", badDesiredPresentFrames);
const auto iter = deltas.find("present2present");
if (iter != deltas.end()) {
StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
@@ -112,8 +114,14 @@
StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
StringAppendF(&result, "presentToPresent histogram is as below:\n");
result.append(presentToPresent.toString());
+ const float averageFrameDuration = frameDuration.averageTime();
+ StringAppendF(&result, "averageFrameDuration = %.3f ms\n",
+ std::isnan(averageFrameDuration) ? 0.0f : averageFrameDuration);
StringAppendF(&result, "frameDuration histogram is as below:\n");
result.append(frameDuration.toString());
+ const float averageRenderEngineTiming = renderEngineTiming.averageTime();
+ StringAppendF(&result, "averageRenderEngineTiming = %.3f ms\n",
+ std::isnan(averageRenderEngineTiming) ? 0.0f : averageRenderEngineTiming);
StringAppendF(&result, "renderEngineTiming histogram is as below:\n");
result.append(renderEngineTiming.toString());
const auto dumpStats = generateDumpStats(maxLayers);
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 702c50e..e374b73 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -46,6 +46,8 @@
std::string packageName;
int32_t totalFrames = 0;
int32_t droppedFrames = 0;
+ int32_t lateAcquireFrames = 0;
+ int32_t badDesiredPresentFrames = 0;
std::unordered_map<std::string, Histogram> deltas;
std::string toString() const;
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index ed2b220..0653959 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -301,18 +301,6 @@
prop_name: "ro.surface_flinger.display_primary_white"
}
-# refreshRateSwitching indicates whether SurfaceFlinger should use refresh rate
-# switching on the device, e.g. to switch between 60 and 90 Hz. The settings
-# below that are related to refresh rate switching will only have an effect if
-# refresh_rate_switching is enabled.
-prop {
- api_name: "refresh_rate_switching"
- type: Boolean
- scope: System
- access: Readonly
- prop_name: "ro.surface_flinger.refresh_rate_switching"
-}
-
prop {
api_name: "set_idle_timer_ms"
type: Integer
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index d24ad18..1adab84 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -73,10 +73,6 @@
enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
}
prop {
- api_name: "refresh_rate_switching"
- prop_name: "ro.surface_flinger.refresh_rate_switching"
- }
- prop {
api_name: "running_without_sync_framework"
prop_name: "ro.surface_flinger.running_without_sync_framework"
}
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index f339ab0..507d28b 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -1,20 +1,15 @@
-#include <algorithm>
-#include <functional>
-#include <limits>
-#include <ostream>
-
#include <gtest/gtest.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-
#include <private/android_filesystem_config.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <utils/String8.h>
+#include <functional>
+
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
@@ -67,14 +62,13 @@
mDisplay = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(mDisplay == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
- const ssize_t displayWidth = info.w;
- const ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
// Background surface
mBGSurfaceControl =
- mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+ mComposerClient->createSurface(SURFACE_NAME, config.resolution.getWidth(),
+ config.resolution.getHeight(),
PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
@@ -188,10 +182,10 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_TRUE(display != nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display));
@@ -255,17 +249,6 @@
ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
}
-TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) {
- setupVirtualDisplay();
-
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
- SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
- // This test currently fails. TODO(b/112002626): Find a way to properly create
- // a display in the test environment, so that destroy display can remove it.
- ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
-}
-
TEST_F(CredentialsTest, CaptureTest) {
const auto display = SurfaceComposerClient::getInternalDisplayToken();
std::function<status_t()> condition = [=]() {
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 3aa4474..0ed2ffb 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -46,24 +46,25 @@
&initialMin, &initialMax);
ASSERT_EQ(res, NO_ERROR);
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
ASSERT_EQ(res, NO_ERROR);
for (size_t i = 0; i < configs.size(); i++) {
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i, configs[i].fps,
- configs[i].fps);
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
+ configs[i].refreshRate,
+ configs[i].refreshRate);
ASSERT_EQ(res, NO_ERROR);
int defaultConfig;
- float minFps;
- float maxFps;
+ float minRefreshRate;
+ float maxRefreshRate;
res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
- &minFps, &maxFps);
+ &minRefreshRate, &maxRefreshRate);
ASSERT_EQ(res, NO_ERROR);
ASSERT_EQ(defaultConfig, i);
- ASSERT_EQ(minFps, configs[i].fps);
- ASSERT_EQ(maxFps, configs[i].fps);
+ ASSERT_EQ(minRefreshRate, configs[i].refreshRate);
+ ASSERT_EQ(maxRefreshRate, configs[i].refreshRate);
}
res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 8a756a6..4023c66 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -14,24 +14,20 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
-
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-
+#include <gtest/gtest.h>
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+#include <utils/String8.h>
#include <limits>
-#include <ui/DisplayInfo.h>
-
-#include <utils/String8.h>
-
#include "BufferGenerator.h"
#include "utils/CallbackUtils.h"
#include "utils/ColorUtils.h"
@@ -231,10 +227,10 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck());
mPrimaryDisplay = mClient->getInternalDisplayToken();
- DisplayInfo info;
- mClient->getDisplayInfo(mPrimaryDisplay, &info);
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
+ DisplayConfig config;
+ mClient->getActiveDisplayConfig(mPrimaryDisplay, &config);
+ mDisplayWidth = config.resolution.getWidth();
+ mDisplayHeight = config.resolution.getHeight();
Transaction setupTransaction;
setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index f7a6d96..5eb1739 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -13,17 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#ifndef ANDROID_LAYER_TRANSACTION_TEST_H
-#define ANDROID_LAYER_TRANSACTION_TEST_H
+
+#pragma once
#include <gtest/gtest.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <hardware/hwcomposer_defs.h>
#include <private/gui/ComposerService.h>
-
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include "BufferGenerator.h"
#include "utils/ScreenshotUtils.h"
@@ -255,18 +253,16 @@
mDisplay = mClient->getInternalDisplayToken();
ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
- // get display width/height
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
- mDisplayRect =
- Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
+ mDisplayRect = Rect(config.resolution);
+ mDisplayWidth = mDisplayRect.getWidth();
+ mDisplayHeight = mDisplayRect.getHeight();
// After a new buffer is queued, SurfaceFlinger is notified and will
// latch the new buffer on next vsync. Let's heuristically wait for 3
// vsyncs.
- mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
+ mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
mDisplayLayerStack = 0;
@@ -295,6 +291,5 @@
friend class LayerRenderPathTestHarness;
};
-} // namespace android
-#endif
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 0459386..a1c4128 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -36,14 +36,13 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
// Background surface
- mBGSurfaceControl = createLayer(String8("BG Test Surface"), displayWidth, displayHeight, 0);
+ mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
+ resolution.getHeight(), 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
@@ -73,7 +72,8 @@
.show(mFGSurfaceControl);
t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
- .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2)
+ .setPosition(mSyncSurfaceControl, resolution.getWidth() - 2,
+ resolution.getHeight() - 2)
.show(mSyncSurfaceControl);
});
}
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index e525e2a..c9fdc3b 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -18,6 +18,8 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
+#include <ui/DisplayState.h>
+
#include "LayerTransactionTest.h"
namespace android {
@@ -34,12 +36,14 @@
ASSERT_EQ(NO_ERROR, mClient->initCheck());
mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
+ SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState);
+ SurfaceComposerClient::getActiveDisplayConfig(mMainDisplay, &mMainDisplayConfig);
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&mProducer, &consumer);
consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
+ consumer->setDefaultBufferSize(mMainDisplayConfig.resolution.getWidth(),
+ mMainDisplayConfig.resolution.getHeight());
}
virtual void TearDown() {
@@ -48,14 +52,14 @@
mColorLayer = 0;
}
- void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
+ void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) {
mVirtualDisplay =
SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
asTransaction([&](Transaction& t) {
t.setDisplaySurface(mVirtualDisplay, mProducer);
t.setDisplayLayerStack(mVirtualDisplay, layerStack);
- t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
- Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
+ t.setDisplayProjection(mVirtualDisplay, mMainDisplayState.orientation,
+ Rect(layerStackSize), Rect(mMainDisplayConfig.resolution));
});
}
@@ -76,7 +80,8 @@
});
}
- DisplayInfo mMainDisplayInfo;
+ ui::DisplayState mMainDisplayState;
+ DisplayConfig mMainDisplayConfig;
sp<IBinder> mMainDisplay;
sp<IBinder> mVirtualDisplay;
sp<IGraphicBufferProducer> mProducer;
@@ -85,7 +90,7 @@
};
TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
+ createDisplay(mMainDisplayState.viewport, 1 /* layerStack */);
createColorLayer(1 /* layerStack */);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
@@ -108,7 +113,7 @@
// Assumption here is that the new mirrored display has the same viewport as the
// primary display that it is mirroring.
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
+ createDisplay(mMainDisplayState.viewport, 0 /* layerStack */);
createColorLayer(0 /* layerStack */);
asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 4a2ab7c..0e7eba8 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -20,18 +20,13 @@
#include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
-
#include <gtest/gtest.h>
-
-#include <android/native_window.h>
-
#include <gui/ISurfaceComposer.h>
#include <gui/LayerState.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <fstream>
#include <random>
@@ -271,21 +266,21 @@
const auto display = SurfaceComposerClient::getInternalDisplayToken();
ASSERT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
// Background surface
- mBGSurfaceControl = mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), displayWidth,
- displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+ mBGSurfaceControl =
+ mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), resolution.getWidth(),
+ resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
// Foreground surface
- mFGSurfaceControl = mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), displayWidth,
- displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+ mFGSurfaceControl =
+ mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), resolution.getWidth(),
+ resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mFGSurfaceControl != nullptr);
ASSERT_TRUE(mFGSurfaceControl->isValid());
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 5612bb2..040852f 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -16,41 +16,10 @@
#ifndef ANDROID_TRANSACTION_TEST_HARNESSES
#define ANDROID_TRANSACTION_TEST_HARNESSES
-/*#include <algorithm>
-#include <chrono>
-#include <cinttypes>
-#include <functional>
-#include <limits>
-#include <ostream>
+#include <ui/DisplayState.h>
-#include <android/native_window.h>
-
-#include <binder/ProcessState.h>
-#include <gui/BufferItemConsumer.h>
-#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/LayerState.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <hardware/hwcomposer_defs.h>
-#include <private/android_filesystem_config.h>
-#include <private/gui/ComposerService.h>
-
-#include <ui/DisplayInfo.h>
-
-#include <math.h>
-#include <math/vec3.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "BufferGenerator.h"
-*/
#include "LayerTransactionTest.h"
-/*#include "utils/CallbackUtils.h"
-#include "utils/ColorUtils.h"
-#include "utils/ScreenshotUtils.h"
-#include "utils/TransactionUtils.h"
-*/
+
namespace android {
using android::hardware::graphics::common::V1_1::BufferUsage;
@@ -66,9 +35,14 @@
return mDelegate->screenshot();
case RenderPath::VIRTUAL_DISPLAY:
- const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- DisplayInfo mainDisplayInfo;
- SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
+ const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+
+ ui::DisplayState displayState;
+ SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+
+ DisplayConfig displayConfig;
+ SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+ const ui::Size& resolution = displayConfig.resolution;
sp<IBinder> vDisplay;
sp<IGraphicBufferProducer> producer;
@@ -77,7 +51,7 @@
BufferQueue::createBufferQueue(&producer, &consumer);
consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
+ consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
itemConsumer = new BufferItemConsumer(consumer,
// Sample usage bits from screenrecord
@@ -90,9 +64,8 @@
SurfaceComposerClient::Transaction t;
t.setDisplaySurface(vDisplay, producer);
t.setDisplayLayerStack(vDisplay, 0);
- t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
- Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
- Rect(mainDisplayInfo.w, mainDisplayInfo.h));
+ t.setDisplayProjection(vDisplay, displayState.orientation,
+ Rect(displayState.viewport), Rect(resolution));
t.apply();
SurfaceComposerClient::Transaction().apply(true);
BufferItem item;
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 6874f6f..e751496 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -41,7 +41,7 @@
#include <hwbinder/ProcessState.h>
#include <log/log.h>
#include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
#include <utils/Looper.h>
#include <gmock/gmock.h>
@@ -338,15 +338,16 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(200u, info.w);
- EXPECT_EQ(400u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ const ui::Size& resolution = config.resolution;
+ EXPECT_EQ(ui::Size(200, 400), resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -369,8 +370,8 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_TRUE(display == nullptr);
- DisplayInfo info;
- EXPECT_NE(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+ DisplayConfig config;
+ EXPECT_NE(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
}
}
@@ -398,17 +399,18 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(200u, info.w);
- EXPECT_EQ(400u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(200, 400), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -421,7 +423,7 @@
}
}
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
EXPECT_EQ(configs.size(), 2);
@@ -436,27 +438,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].w == 800u) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 800) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -500,17 +504,18 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -523,7 +528,7 @@
}
}
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
EXPECT_EQ(configs.size(), 2);
@@ -537,27 +542,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].fps == 1e9f / 11'111'111) {
+ const auto& config = configs[i];
+ if (config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -611,17 +618,18 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ DisplayConfig config;
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -634,7 +642,7 @@
}
}
- Vector<DisplayInfo> configs;
+ Vector<DisplayConfig> configs;
EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
EXPECT_EQ(configs.size(), 4);
@@ -648,27 +656,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].w == 800u && configs[i].fps == 1e9f / 11'111'111) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ configs[i].refreshRate,
+ configs[i].refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(800u, info.w);
- EXPECT_EQ(1600u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -691,27 +701,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].fps == 1e9f / 8'333'333) {
+ const auto& config = configs[i];
+ if (config.refreshRate == 1e9f / 8'333'333) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(1600u, info.w);
- EXPECT_EQ(3200u, info.h);
- EXPECT_EQ(1e9f / 8'333'333, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+ EXPECT_EQ(1e9f / 8'333'333, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -734,27 +746,29 @@
}
for (int i = 0; i < configs.size(); i++) {
- if (configs[i].w == 1600 && configs[i].fps == 1e9f / 11'111'111) {
+ const auto& config = configs[i];
+ if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
EXPECT_EQ(NO_ERROR,
SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
- configs[i].fps,
- configs[i].fps));
+ config.refreshRate,
+ config.refreshRate));
waitForDisplayTransaction();
EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
break;
}
}
- EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
- EXPECT_EQ(1600u, info.w);
- EXPECT_EQ(3200u, info.h);
- EXPECT_EQ(1e9f / 11'111'111, info.fps);
+ EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+ EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+ EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
mFakeComposerClient->clearFrames();
{
+ const ui::Size& resolution = config.resolution;
auto surfaceControl =
- mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w,
- info.h, PIXEL_FORMAT_RGBA_8888, 0);
+ mComposerClient->createSurface(String8("Display Test Surface Foo"),
+ resolution.getWidth(), resolution.getHeight(),
+ PIXEL_FORMAT_RGBA_8888, 0);
EXPECT_TRUE(surfaceControl != nullptr);
EXPECT_TRUE(surfaceControl->isValid());
fillSurfaceRGBA8(surfaceControl, BLUE);
@@ -787,8 +801,8 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
EXPECT_TRUE(display == nullptr);
- DisplayInfo info;
- auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+ DisplayConfig config;
+ auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
EXPECT_NE(NO_ERROR, result);
}
@@ -813,12 +827,11 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
EXPECT_FALSE(display == nullptr);
- DisplayInfo info;
- auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
+ DisplayConfig config;
+ auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
EXPECT_EQ(NO_ERROR, result);
- ASSERT_EQ(400u, info.w);
- ASSERT_EQ(200u, info.h);
- EXPECT_EQ(1e9f / 16'666'666, info.fps);
+ ASSERT_EQ(ui::Size(400, 200), config.resolution);
+ EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
}
}
@@ -968,11 +981,12 @@
const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
ASSERT_FALSE(display == nullptr);
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+ DisplayConfig config;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
+ const ui::Size& resolution = config.resolution;
+ mDisplayWidth = resolution.getWidth();
+ mDisplayHeight = resolution.getHeight();
// Background surface
mBGSurfaceControl =
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 7681283..d046f76 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -32,7 +32,6 @@
// option to false temporarily.
address: true,
},
- data: ["libsurfaceflinger_unittest.filter"],
srcs: [
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 98cc023..c6d8a2e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -713,7 +713,9 @@
struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
-struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {};
+struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {
+ static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
+};
struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerProperties> {
using Base = BaseLayerProperties<SidebandLayerProperties>;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 9680a17..dddad92 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -1357,7 +1357,8 @@
mHardwareDisplaySize.height),
compositionState.transform);
EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
EXPECT_EQ(false, compositionState.needsFiltering);
@@ -1369,7 +1370,8 @@
mHardwareDisplaySize.height),
compositionState.transform);
EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
// For 90, the frame and viewport have the hardware display size width and height swapped
EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
@@ -1382,7 +1384,8 @@
mHardwareDisplaySize.height),
compositionState.transform);
EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
EXPECT_EQ(false, compositionState.needsFiltering);
@@ -1394,7 +1397,8 @@
mHardwareDisplaySize.height),
compositionState.transform);
EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
- EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.scissor);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+ EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
// For 270, the frame and viewport have the hardware display size width and height swapped
EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 9ca1b70..18e9941 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -63,8 +63,7 @@
auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
- RefreshRateConfigs mConfigs{true,
- {
+ RefreshRateConfigs mConfigs{{
RefreshRateConfigs::InputConfig{HwcConfigIndexType(0),
HwcConfigGroupType(0),
LO_FPS_PERIOD},
@@ -85,7 +84,7 @@
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -114,7 +113,7 @@
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -138,15 +137,15 @@
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
nsecs_t time = mTime;
EXPECT_EQ(3, layerCount());
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 11ace05..959c256 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -71,8 +71,7 @@
auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
- RefreshRateConfigs mConfigs{true,
- {
+ RefreshRateConfigs mConfigs{{
RefreshRateConfigs::InputConfig{HwcConfigIndexType(0),
HwcConfigGroupType(0),
LO_FPS_PERIOD},
@@ -84,7 +83,6 @@
TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)};
TestableSurfaceFlinger mFlinger;
- const nsecs_t mTime = systemTime();
};
namespace {
@@ -92,28 +90,30 @@
TEST_F(LayerHistoryTestV2, oneLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
+ const nsecs_t time = systemTime();
+
// No layers returned if no layers are active.
- EXPECT_TRUE(history().summarize(mTime).empty());
+ EXPECT_TRUE(history().summarize(time).empty());
EXPECT_EQ(0, activeLayerCount());
// Max returned if active layers have insufficient history.
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
- history().record(layer.get(), 0, mTime);
- ASSERT_EQ(1, history().summarize(mTime).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ history().record(layer.get(), 0, time);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
// Max is returned since we have enough history but there is no timestamp votes.
for (int i = 0; i < 10; i++) {
- history().record(layer.get(), 0, mTime);
- ASSERT_EQ(1, history().summarize(mTime).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ history().record(layer.get(), 0, time);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
}
}
@@ -121,33 +121,36 @@
TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- history().record(layer.get(), 0, mTime);
- auto summary = history().summarize(mTime);
- ASSERT_EQ(1, history().summarize(mTime).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote);
+ nsecs_t time = systemTime();
+
+ history().record(layer.get(), 0, time);
+ auto summary = history().summarize(time);
+ ASSERT_EQ(1, history().summarize(time).size());
+ // Layer is still considered inactive so we expect to get Min
+ EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
- summary = history().summarize(mTime);
- EXPECT_TRUE(history().summarize(mTime).empty());
+ summary = history().summarize(time);
+ EXPECT_TRUE(history().summarize(time).empty());
EXPECT_EQ(0, activeLayerCount());
}
TEST_F(LayerHistoryTestV2, explicitTimestamp) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += LO_FPS_PERIOD;
@@ -163,14 +166,14 @@
TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += HI_FPS_PERIOD;
@@ -190,14 +193,14 @@
TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += HI_FPS_PERIOD;
@@ -218,14 +221,14 @@
TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max);
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += LO_FPS_PERIOD;
@@ -246,19 +249,53 @@
TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer, getFrameRate()).WillRepeatedly(Return(73.4f));
+ EXPECT_CALL(*layer, getFrameRate())
+ .WillRepeatedly(
+ Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default)));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
history().record(layer.get(), time, time);
time += HI_FPS_PERIOD;
}
ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Explicit, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
+ EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
+
+ // layer became inactive
+ setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+ time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+ ASSERT_TRUE(history().summarize(time).empty());
+ // TODO: activeLayerCount() should be 0 but it is 1 since getFrameRate() returns a value > 0
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) {
+ auto layer = createLayer();
+ EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*layer, getFrameRate())
+ .WillRepeatedly(Return(
+ Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+ EXPECT_EQ(1, layerCount());
+ EXPECT_EQ(0, activeLayerCount());
+
+ nsecs_t time = systemTime();
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+ history().record(layer.get(), time, time);
+ time += HI_FPS_PERIOD;
+ }
+
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+ history().summarize(time)[0].vote);
EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
EXPECT_EQ(1, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
@@ -278,15 +315,15 @@
auto layer3 = createLayer();
EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer1, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer2, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
- EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt));
+ EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(Layer::FrameRate()));
- nsecs_t time = mTime;
+ nsecs_t time = systemTime();
EXPECT_EQ(3, layerCount());
EXPECT_EQ(0, activeLayerCount());
@@ -314,7 +351,7 @@
ASSERT_EQ(2, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
- EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote);
+ ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote);
EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
EXPECT_EQ(2, activeLayerCount());
EXPECT_EQ(1, frequentLayerCount(time));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 78009b8..841c624 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -74,26 +74,14 @@
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
-}
-
-TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingNotSupported) {
- std::vector<RefreshRateConfigs::InputConfig> configs{
- {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
- auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
}
TEST_F(RefreshRateConfigsTest, invalidPolicy) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
ASSERT_LT(refreshRateConfigs->setPolicy(HwcConfigIndexType(10), 60, 60, nullptr), 0);
ASSERT_LT(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 20, 40, nullptr), 0);
}
@@ -103,10 +91,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
const auto minRate = refreshRateConfigs->getMinRefreshRate();
const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
@@ -128,10 +113,8 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_1, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
const auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
const auto performanceRate = refreshRateConfigs->getMaxRefreshRate();
const auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
@@ -145,7 +128,6 @@
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_90, 60, 90, nullptr), 0);
refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
const auto minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
const auto performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -161,9 +143,8 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
auto minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
auto performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -174,7 +155,6 @@
ASSERT_EQ(expectedPerformanceConfig, performanceRate);
ASSERT_GE(refreshRateConfigs->setPolicy(HWC_CONFIG_ID_60, 60, 60, nullptr), 0);
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
auto minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
auto performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -187,8 +167,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
{
auto current = refreshRateConfigs->getCurrentRefreshRate();
EXPECT_EQ(current.configId, HWC_CONFIG_ID_60);
@@ -212,10 +191,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -276,10 +252,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -387,10 +360,7 @@
{HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 70};
@@ -430,10 +400,7 @@
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
{HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -465,15 +432,83 @@
EXPECT_EQ(expected72Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
+TEST_F(RefreshRateConfigsTest,
+ twoDeviceConfigs_getRefreshRateForContentV2_30_60_90_120_DifferentTypes) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30},
+ {HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90},
+ {HWC_CONFIG_ID_120, HWC_GROUP_ID_0, VSYNC_120}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected72Config = {HWC_CONFIG_ID_72, VSYNC_72, HWC_GROUP_ID_0, "72fps", 72};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+ RefreshRate expected120Config = {HWC_CONFIG_ID_120, VSYNC_120, HWC_GROUP_ID_0, "120fps", 120};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+ LayerRequirement{.weight = 1.0f}};
+ auto& lr1 = layers[0];
+ auto& lr2 = layers[1];
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 60.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::Heuristic;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::Heuristic;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitDefault;
+ EXPECT_EQ(expected120Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+
+ lr1.desiredRefreshRate = 24.0f;
+ lr1.vote = LayerVoteType::ExplicitDefault;
+ lr2.desiredRefreshRate = 90.0f;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+ EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+}
+
TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_30_60) {
std::vector<RefreshRateConfigs::InputConfig> configs{
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_30, HWC_GROUP_ID_0, VSYNC_30}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
@@ -495,7 +530,7 @@
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr.desiredRefreshRate = 45.0f;
- EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
+ EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr.desiredRefreshRate = 30.0f;
EXPECT_EQ(expected30Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -511,10 +546,7 @@
{HWC_CONFIG_ID_72, HWC_GROUP_ID_0, VSYNC_72},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -553,10 +585,7 @@
{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -577,7 +606,7 @@
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Min;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 24.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -587,7 +616,7 @@
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Max;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
@@ -599,7 +628,7 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 30.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 45.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
@@ -609,10 +638,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
@@ -621,7 +647,7 @@
auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
auto& lr = layers[0];
- lr.vote = LayerVoteType::Explicit;
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
lr.desiredRefreshRate = fps;
const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
@@ -635,10 +661,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -650,13 +673,13 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 60.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContent(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
}
@@ -666,10 +689,7 @@
{{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
{HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
auto refreshRateConfigs =
- std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
- /*currentConfigId=*/HWC_CONFIG_ID_60);
-
- ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
@@ -681,13 +701,13 @@
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 60.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 90.0f;
EXPECT_EQ(expected90Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
lr1.vote = LayerVoteType::Heuristic;
lr1.desiredRefreshRate = 90.0f;
- lr2.vote = LayerVoteType::Explicit;
+ lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
lr2.desiredRefreshRate = 60.0f;
EXPECT_EQ(expected60Config, refreshRateConfigs->getRefreshRateForContentV2(layers));
}
@@ -702,6 +722,29 @@
ASSERT_FALSE(expectedDefaultConfig.inPolicy(50.0f, 59.998f));
}
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContentV2_75HzContent) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{
+ {{HWC_CONFIG_ID_60, HWC_GROUP_ID_0, VSYNC_60},
+ {HWC_CONFIG_ID_90, HWC_GROUP_ID_0, VSYNC_90}}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+ RefreshRate expected30Config = {HWC_CONFIG_ID_30, VSYNC_30, HWC_GROUP_ID_0, "30fps", 30};
+ RefreshRate expected60Config = {HWC_CONFIG_ID_60, VSYNC_60, HWC_GROUP_ID_0, "60fps", 60};
+ RefreshRate expected90Config = {HWC_CONFIG_ID_90, VSYNC_90, HWC_GROUP_ID_0, "90fps", 90};
+
+ auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+ auto& lr = layers[0];
+
+ lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+ for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
+ lr.desiredRefreshRate = fps;
+ const auto& refreshRate = refreshRateConfigs->getRefreshRateForContentV2(layers);
+ printf("%.2fHz chooses %s\n", fps, refreshRate.name.c_str());
+ EXPECT_EQ(expected90Config, refreshRate);
+ }
+}
+
} // namespace
} // namespace scheduler
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 8e07c79..18d6bd2 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -47,8 +47,8 @@
~RefreshRateStatsTest();
void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) {
- mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>(
- /*refreshRateSwitching=*/true, configs, /*currentConfig=*/CONFIG_ID_0);
+ mRefreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
mRefreshRateStats =
std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
/*currentConfigId=*/CONFIG_ID_0,
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 82a00ee..89002a8 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -73,8 +73,7 @@
std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{
{{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}};
mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfig=*/HwcConfigIndexType(0));
+ scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs, false);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2491533..be233bb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -203,8 +203,7 @@
std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{
{{HwcConfigIndexType(0), HwcConfigGroupType(0), 16666667}}};
mFlinger->mRefreshRateConfigs = std::make_unique<
- scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
- /*currentConfig=*/HwcConfigIndexType(0));
+ scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
mFlinger->mRefreshRateStats = std::make_unique<
scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
/*currentConfig=*/HwcConfigIndexType(0),
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 68e6697..30505b9 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -37,6 +37,7 @@
using namespace android::surfaceflinger;
using namespace google::protobuf;
+using namespace std::chrono_literals;
namespace android {
namespace {
@@ -258,22 +259,25 @@
ASSERT_FALSE(mTimeStats->isEnabled());
}
-TEST_F(TimeStatsTest, enabledAfterBoot) {
+TEST_F(TimeStatsTest, registersCallbacksAfterBoot) {
mTimeStats->onBootFinished();
- ASSERT_TRUE(mTimeStats->isEnabled());
+ EXPECT_THAT(mDelegate->mAtomTags,
+ UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+ android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+}
+
+TEST_F(TimeStatsTest, unregistersCallbacksOnDestruction) {
+ EXPECT_CALL(*mDelegate,
+ unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+ EXPECT_CALL(*mDelegate,
+ unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+ mTimeStats.reset();
}
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
- EXPECT_THAT(mDelegate->mAtomTags,
- UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
- android::util::SURFACEFLINGER_STATS_LAYER_INFO));
- EXPECT_CALL(*mDelegate,
- unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
- EXPECT_CALL(*mDelegate,
- unregisterStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
EXPECT_TRUE(inputCommand(InputCommand::DISABLE, FMT_STRING).empty());
ASSERT_FALSE(mTimeStats->isEnabled());
}
@@ -306,6 +310,41 @@
EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
}
+TEST_F(TimeStatsTest, canIncreaseLateAcquireFrames) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t LATE_ACQUIRE_FRAMES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
+ mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
+ }
+ insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult = "lateAcquireFrames = " + std::to_string(LATE_ACQUIRE_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseBadDesiredPresent) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+ insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+ for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
+ mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
+ }
+ insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "badDesiredPresentFrames = " + std::to_string(BAD_DESIRED_PRESENT_FRAMES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
// this stat is not in the proto so verify by checking the string dump
constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
@@ -321,6 +360,45 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
+TEST_F(TimeStatsTest, canAverageFrameDuration) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(16ms)
+ .count());
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("averageFrameDuration = 10.000 ms"));
+}
+
+TEST_F(TimeStatsTest, canAverageRenderEngineTimings) {
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
+ .count(),
+ std::make_shared<FenceTime>(
+ std::chrono::duration_cast<
+ std::chrono::nanoseconds>(3ms)
+ .count()));
+
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(8ms)
+ .count());
+
+ // Push a dummy present fence to trigger flushing the RenderEngine timings.
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 3.000 ms"));
+}
+
TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
@@ -353,8 +431,6 @@
TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- using namespace std::chrono_literals;
-
mTimeStats->setPowerMode(HWC_POWER_MODE_OFF);
mTimeStats
->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
@@ -378,8 +454,6 @@
TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
- using namespace std::chrono_literals;
-
mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
.count(),
std::make_shared<FenceTime>(
@@ -635,7 +709,6 @@
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
- using namespace std::chrono_literals;
mTimeStats
->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
@@ -665,14 +738,27 @@
EXPECT_EQ(0, globalProto.stats_size());
}
-TEST_F(TimeStatsTest, canClearClientCompositionSkippedFrames) {
- // this stat is not in the proto so verify by checking the string dump
+TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
+ // These stats are not in the proto so verify by checking the string dump.
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ mTimeStats
+ ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
+ .count());
+ mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+ .count(),
+ std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+ .count());
+ mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
+ EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
+ EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
}
TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
diff --git a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter b/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter
deleted file mode 100644
index 8e9c3cf..0000000
--- a/services/surfaceflinger/tests/unittests/libsurfaceflinger_unittest.filter
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- // TODO(b/148517641): re-enable once this test is fixed
- "presubmit": {
- "filter": "*:-FrameTracerTest.*"
- }
-}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
index 494e73d..e2f6abd 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -31,7 +31,7 @@
MOCK_METHOD0(getFrameSelectionPriority, int32_t());
MOCK_CONST_METHOD0(isVisible, bool());
MOCK_METHOD0(createClone, sp<Layer>());
- MOCK_CONST_METHOD0(getFrameRate, std::optional<float>());
+ MOCK_CONST_METHOD0(getFrameRate, FrameRate());
};
} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index d1df08c..2720537 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -40,6 +40,8 @@
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));
MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
+ MOCK_METHOD2(incrementLatchSkipped, void(int32_t layerId, LatchSkipReason reason));
+ MOCK_METHOD1(incrementBadDesiredPresent, void(int32_t layerId));
MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 90a73e2..a7ec4ae 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -164,6 +164,11 @@
"ro.board.platform",
}};
+// LoadDriver returns:
+// * 0 when succeed, or
+// * -ENOENT when fail to open binary libraries, or
+// * -EINVAL when fail to find HAL_MODULE_INFO_SYM_AS_STR or
+// HWVULKAN_HARDWARE_MODULE_ID in the library.
int LoadDriver(android_namespace_t* library_namespace,
const hwvulkan_module_t** module) {
ATRACE_CALL();
@@ -221,7 +226,13 @@
return -ENOENT;
android::GraphicsEnv::getInstance().setDriverToLoad(
android::GpuStatsInfo::Driver::VULKAN_UPDATED);
- return LoadDriver(ns, module);
+ int result = LoadDriver(ns, module);
+ if (result != 0) {
+ LOG_ALWAYS_FATAL(
+ "couldn't find an updated Vulkan implementation from %s",
+ android::GraphicsEnv::getInstance().getDriverPath().c_str());
+ }
+ return result;
}
bool Hal::Open() {