Merge "Pass in window name along with focus request"
diff --git a/.gitignore b/.gitignore
index 685e379..ed653c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
*.iml
*.pyc
.idea/
+.vscode/
+*.code-workspace
diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp
index b1bc6dc..627dfe6 100644
--- a/cmds/servicemanager/main.cpp
+++ b/cmds/servicemanager/main.cpp
@@ -45,10 +45,6 @@
IPCThreadState::self()->setupPolling(&binder_fd);
LOG_ALWAYS_FATAL_IF(binder_fd < 0, "Failed to setupPolling: %d", binder_fd);
- // Flush after setupPolling(), to make sure the binder driver
- // knows about this thread handling commands.
- IPCThreadState::self()->flushCommands();
-
int ret = looper->addFd(binder_fd,
Looper::POLL_CALLBACK,
Looper::EVENT_INPUT,
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 7d01e0b..b038feb 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -489,12 +489,14 @@
void IPCThreadState::blockUntilThreadAvailable()
{
pthread_mutex_lock(&mProcess->mThreadCountLock);
+ mProcess->mWaitingForThreads++;
while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) {
ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n",
static_cast<unsigned long>(mProcess->mExecutingThreadsCount),
static_cast<unsigned long>(mProcess->mMaxThreads));
pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock);
}
+ mProcess->mWaitingForThreads--;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
@@ -534,7 +536,12 @@
}
mProcess->mStarvationStartTimeMs = 0;
}
- pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
+
+ // Cond broadcast can be expensive, so don't send it every time a binder
+ // call is processed. b/168806193
+ if (mProcess->mWaitingForThreads > 0) {
+ pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
+ }
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
@@ -629,6 +636,7 @@
}
mOut.writeInt32(BC_ENTER_LOOPER);
+ flushCommands();
*fd = mProcess->mDriverFD;
return 0;
}
diff --git a/libs/binder/LazyServiceRegistrar.cpp b/libs/binder/LazyServiceRegistrar.cpp
index 1173138..f96b6bb 100644
--- a/libs/binder/LazyServiceRegistrar.cpp
+++ b/libs/binder/LazyServiceRegistrar.cpp
@@ -38,8 +38,7 @@
bool allowIsolated, int dumpFlags);
void forcePersist(bool persist);
- void setActiveServicesCountCallback(const std::function<bool(int)>&
- activeServicesCountCallback);
+ void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
bool tryUnregister();
@@ -82,13 +81,16 @@
// count of services with clients
size_t mNumConnectedServices;
+ // previous value passed to the active services callback
+ std::optional<bool> mPreviousHasClients;
+
// map of registered names and services
std::map<std::string, Service> mRegisteredServices;
bool mForcePersist;
- // Callback used to report the number of services with clients
- std::function<bool(int)> mActiveServicesCountCallback;
+ // Callback used to report if there are services with clients
+ std::function<bool(bool)> mActiveServicesCallback;
};
class ClientCounterCallback {
@@ -103,8 +105,7 @@
*/
void forcePersist(bool persist);
- void setActiveServicesCountCallback(const std::function<bool(int)>&
- activeServicesCountCallback);
+ void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
bool tryUnregister();
@@ -158,7 +159,7 @@
void ClientCounterCallbackImpl::forcePersist(bool persist) {
mForcePersist = persist;
- if (!mForcePersist && mNumConnectedServices == 0) {
+ if (!mForcePersist) {
// Attempt a shutdown in case the number of clients hit 0 while the flag was on
maybeTryShutdown();
}
@@ -204,8 +205,12 @@
}
bool handledInCallback = false;
- if (mActiveServicesCountCallback != nullptr) {
- handledInCallback = mActiveServicesCountCallback(mNumConnectedServices);
+ if (mActiveServicesCallback != nullptr) {
+ bool hasClients = mNumConnectedServices != 0;
+ if (hasClients != mPreviousHasClients) {
+ handledInCallback = mActiveServicesCallback(hasClients);
+ mPreviousHasClients = hasClients;
+ }
}
// If there is no callback defined or the callback did not handle this
@@ -256,9 +261,9 @@
reRegister();
}
-void ClientCounterCallbackImpl::setActiveServicesCountCallback(const std::function<bool(int)>&
- activeServicesCountCallback) {
- mActiveServicesCountCallback = activeServicesCountCallback;
+void ClientCounterCallbackImpl::setActiveServicesCallback(const std::function<bool(bool)>&
+ activeServicesCallback) {
+ mActiveServicesCallback = activeServicesCallback;
}
ClientCounterCallback::ClientCounterCallback() {
@@ -274,9 +279,9 @@
mImpl->forcePersist(persist);
}
-void ClientCounterCallback::setActiveServicesCountCallback(const std::function<bool(int)>&
- activeServicesCountCallback) {
- mImpl->setActiveServicesCountCallback(activeServicesCountCallback);
+void ClientCounterCallback::setActiveServicesCallback(const std::function<bool(bool)>&
+ activeServicesCallback) {
+ mImpl->setActiveServicesCallback(activeServicesCallback);
}
bool ClientCounterCallback::tryUnregister() {
@@ -310,9 +315,9 @@
mClientCC->forcePersist(persist);
}
-void LazyServiceRegistrar::setActiveServicesCountCallback(const std::function<bool(int)>&
- activeServicesCountCallback) {
- mClientCC->setActiveServicesCountCallback(activeServicesCountCallback);
+void LazyServiceRegistrar::setActiveServicesCallback(const std::function<bool(bool)>&
+ activeServicesCallback) {
+ mClientCC->setActiveServicesCallback(activeServicesCallback);
}
bool LazyServiceRegistrar::tryUnregister() {
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index b5e4dfe..c38249e 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -399,6 +399,7 @@
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
+ , mWaitingForThreads(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mStarvationStartTimeMs(0)
, mThreadPoolStarted(false)
diff --git a/libs/binder/include/binder/LazyServiceRegistrar.h b/libs/binder/include/binder/LazyServiceRegistrar.h
index 73893c7..9659732 100644
--- a/libs/binder/include/binder/LazyServiceRegistrar.h
+++ b/libs/binder/include/binder/LazyServiceRegistrar.h
@@ -56,10 +56,10 @@
void forcePersist(bool persist);
/**
- * Set a callback that is executed when the total number of services with
- * clients changes.
- * The callback takes an argument, which is the number of registered
- * lazy services for this process which have clients.
+ * Set a callback that is invoked when the active service count (i.e. services with clients)
+ * registered with this process drops to zero (or becomes nonzero).
+ * The callback takes a boolean argument, which is 'true' if there is
+ * at least one service with clients.
*
* Callback return value:
* - false: Default behavior for lazy services (shut down the process if there
@@ -73,8 +73,7 @@
*
* This method should be called before 'registerService' to avoid races.
*/
- void setActiveServicesCountCallback(const std::function<bool(int)>&
- activeServicesCountCallback);
+ void setActiveServicesCallback(const std::function<bool(bool)>& activeServicesCallback);
/**
* Try to unregister all services previously registered with 'registerService'.
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index bab6469..2405ab6 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -107,11 +107,14 @@
int mDriverFD;
void* mVMStart;
- // Protects thread count variable below.
+ // Protects thread count and wait variables below.
pthread_mutex_t mThreadCountLock;
+ // Broadcast whenever mWaitingForThreads > 0
pthread_cond_t mThreadCountDecrement;
// Number of binder threads current executing a command.
size_t mExecutingThreadsCount;
+ // Number of threads calling IPCThreadState::blockUntilThreadAvailable()
+ size_t mWaitingForThreads;
// Maximum number for binder threads allowed for this process.
size_t mMaxThreads;
// Time when thread pool was emptied
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 53871f2..0ad400b 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -259,10 +259,24 @@
const char* getMessage() const { return AStatus_getMessage(get()); }
std::string getDescription() const {
- const char* cStr = AStatus_getDescription(get());
- std::string ret = cStr;
- AStatus_deleteDescription(cStr);
- return ret;
+ if (__builtin_available(android 30, *)) {
+ const char* cStr = AStatus_getDescription(get());
+ std::string ret = cStr;
+ AStatus_deleteDescription(cStr);
+ return ret;
+ }
+ binder_exception_t exception = getExceptionCode();
+ std::string desc = std::to_string(exception);
+ if (exception == EX_SERVICE_SPECIFIC) {
+ desc += " (" + std::to_string(getServiceSpecificError()) + ")";
+ } else if (exception == EX_TRANSACTION_FAILED) {
+ desc += " (" + std::to_string(getStatus()) + ")";
+ }
+ if (const char* msg = getMessage(); msg != nullptr) {
+ desc += ": ";
+ desc += msg;
+ }
+ return desc;
}
/**
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index a1102e2..05eb64b 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -247,7 +247,7 @@
// ourselves. The defaults are harmless.
AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
#ifdef HAS_BINDER_SHELL_COMMAND
- if (AIBinder_Class_setHandleShellCommand != nullptr) {
+ if (__builtin_available(android 30, *)) {
AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
}
#endif
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 6636a41..2277148 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -51,14 +51,27 @@
binder_status_t writeToParcel(AParcel* parcel) const {
RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
- RETURN_ON_FAILURE(AParcel_writeInt32(parcel, AParcel_getDataSize(this->mParcel.get())));
- RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0,
- AParcel_getDataSize(this->mParcel.get())));
+ if (__builtin_available(android 31, *)) {
+ int32_t size = AParcel_getDataSize(this->mParcel.get());
+ RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
+ } else {
+ return STATUS_INVALID_OPERATION;
+ }
+ if (__builtin_available(android 31, *)) {
+ int32_t size = AParcel_getDataSize(this->mParcel.get());
+ RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
+ } else {
+ return STATUS_INVALID_OPERATION;
+ }
return STATUS_OK;
}
binder_status_t readFromParcel(const AParcel* parcel) {
- AParcel_reset(mParcel.get());
+ if (__builtin_available(android 31, *)) {
+ AParcel_reset(mParcel.get());
+ } else {
+ return STATUS_INVALID_OPERATION;
+ }
RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
int32_t dataSize;
@@ -74,7 +87,11 @@
return STATUS_BAD_VALUE;
}
- status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+ if (__builtin_available(android 31, *)) {
+ status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+ } else {
+ status = STATUS_INVALID_OPERATION;
+ }
if (status != STATUS_OK) {
return status;
}
@@ -86,7 +103,11 @@
if (this->mStability > T::_aidl_stability) {
return STATUS_BAD_VALUE;
}
- AParcel_reset(mParcel.get());
+ if (__builtin_available(android 31, *)) {
+ AParcel_reset(mParcel.get());
+ } else {
+ return STATUS_INVALID_OPERATION;
+ }
AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
p.writeToParcel(mParcel.get());
return STATUS_OK;
@@ -96,9 +117,13 @@
binder_status_t getParcelable(std::optional<T>* ret) const {
const std::string parcelableDesc(T::descriptor);
AParcel_setDataPosition(mParcel.get(), 0);
- if (AParcel_getDataSize(mParcel.get()) == 0) {
- *ret = std::nullopt;
- return STATUS_OK;
+ if (__builtin_available(android 31, *)) {
+ if (AParcel_getDataSize(mParcel.get()) == 0) {
+ *ret = std::nullopt;
+ return STATUS_OK;
+ }
+ } else {
+ return STATUS_INVALID_OPERATION;
}
std::string parcelableDescInParcel;
binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
@@ -115,7 +140,11 @@
return STATUS_OK;
}
- void reset() { AParcel_reset(mParcel.get()); }
+ void reset() {
+ if (__builtin_available(android 31, *)) {
+ AParcel_reset(mParcel.get());
+ }
+ }
inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index 0ca3a07..bb70588 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -660,13 +660,15 @@
/**
* Whether AIBinder is less than another.
*
- * This provides a per-process-unique total ordering of binders determined by
- * an underlying allocation address where a null AIBinder* is considered to be
- * ordered before all other binders.
+ * This provides a per-process-unique total ordering of binders where a null
+ * AIBinder* object is considered to be before all other binder objects.
+ * For instance, two binders refer to the same object in a local or remote
+ * process when both AIBinder_lt(a, b) and AIBinder(b, a) are false. This API
+ * might be used to insert and lookup binders in binary search trees.
*
* AIBinder* pointers themselves actually also create a per-process-unique total
* ordering. However, this ordering is inconsistent with AIBinder_Weak_lt for
- * remote binders.
+ * remote binders. So, in general, this function should be preferred.
*
* Available since API level 31.
*
@@ -698,14 +700,21 @@
* the same as AIBinder_lt. Similarly, a null AIBinder_Weak* is considered to be
* ordered before all other weak references.
*
- * If you have many AIBinder_Weak* objects which are all references to distinct
- * binder objects which happen to have the same underlying address (as ordered
- * by AIBinder_lt), these AIBinder_Weak* objects will retain the same order with
- * respect to all other AIBinder_Weak* pointers with different underlying
- * addresses and are also guaranteed to have a per-process-unique ordering. That
- * is, even though multiple AIBinder* instances may happen to be allocated at
- * the same underlying address, this function will still correctly distinguish
- * that these are weak pointers to different binder objects.
+ * This function correctly distinguishes binders even if one is deallocated. So,
+ * for instance, an AIBinder_Weak* entry representing a deleted binder will
+ * never compare as equal to an AIBinder_Weak* entry which represents a
+ * different allocation of a binder, even if the two binders were originally
+ * allocated at the same address. That is:
+ *
+ * AIBinder* a = ...; // imagine this has address 0x8
+ * AIBinder_Weak* bWeak = AIBinder_Weak_new(a);
+ * AIBinder_decStrong(a); // a may be deleted, if this is the last reference
+ * AIBinder* b = ...; // imagine this has address 0x8 (same address as b)
+ * AIBinder_Weak* bWeak = AIBinder_Weak_new(b);
+ *
+ * Then when a/b are compared with other binders, their order will be preserved,
+ * and it will either be the case that AIBinder_Weak_lt(aWeak, bWeak) OR
+ * AIBinder_Weak_lt(bWeak, aWeak), but not both.
*
* Unlike AIBinder*, the AIBinder_Weak* addresses themselves have nothing to do
* with the underlying binder.
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 93c3f32..ab67017 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1120,7 +1120,6 @@
// @END-PRIMITIVE-READ-WRITE
#endif //__ANDROID_API__ >= 29
-#if __ANDROID_API__ >= 31
/**
* Reset the parcel to the initial status.
*
@@ -1166,7 +1165,6 @@
* \return A parcel which is not related to any IBinder objects.
*/
AParcel* AParcel_create() __INTRODUCED_IN(31);
-#endif //__ANDROID_API__ >= 31
__END_DECLS
/** @} */
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index f4b5a26..0a3d44d 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -117,11 +117,13 @@
}
BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
- int width, int height, bool enableTripleBuffering)
+ int width, int height, int32_t format,
+ bool enableTripleBuffering)
: mName(name),
mSurfaceControl(surface),
mSize(width, height),
mRequestedSize(mSize),
+ mFormat(format),
mNextTransaction(nullptr) {
createBufferQueue(&mProducer, &mConsumer);
// since the adapter is in the client process, set dequeue timeout
@@ -140,7 +142,7 @@
mBufferItemConsumer->setFrameAvailableListener(this);
mBufferItemConsumer->setBufferFreedListener(this);
mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
- mBufferItemConsumer->setDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888);
+ mBufferItemConsumer->setDefaultBufferFormat(format);
mTransformHint = mSurfaceControl->getTransformHint();
mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -164,10 +166,16 @@
t.apply();
}
-void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height) {
+void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
+ int32_t format) {
std::unique_lock _lock{mMutex};
mSurfaceControl = surface;
+ if (mFormat != format) {
+ mFormat = format;
+ mBufferItemConsumer->setDefaultBufferFormat(format);
+ }
+
ui::Size newSize(width, height);
if (mRequestedSize != newSize) {
mRequestedSize.set(newSize);
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 0fbcbdc..411526e 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -68,7 +68,7 @@
{
public:
BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width,
- int height, bool enableTripleBuffering = true);
+ int height, int32_t format, bool enableTripleBuffering = true);
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
return mProducer;
@@ -88,7 +88,7 @@
void setTransactionCompleteCallback(uint64_t frameNumber,
std::function<void(int64_t)>&& transactionCompleteCallback);
- void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height);
+ void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height, int32_t format);
void flushShadowQueue() { mFlushShadowQueue = true; }
status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
@@ -136,6 +136,7 @@
ui::Size mSize GUARDED_BY(mMutex);
ui::Size mRequestedSize GUARDED_BY(mMutex);
+ int32_t mFormat GUARDED_BY(mMutex);
uint32_t mTransformHint GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/JankInfo.h b/libs/gui/include/gui/JankInfo.h
index fc91714..85ae9cb 100644
--- a/libs/gui/include/gui/JankInfo.h
+++ b/libs/gui/include/gui/JankInfo.h
@@ -19,7 +19,6 @@
namespace android {
// Jank information tracked by SurfaceFlinger(SF) for perfetto tracing and telemetry.
-// TODO(b/175843808): Change JankType from enum to enum class
enum JankType {
// No Jank
None = 0x0,
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index d69b7c3..70e656d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -45,11 +45,12 @@
class BLASTBufferQueueHelper {
public:
BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
- mBlastBufferQueueAdapter = new BLASTBufferQueue("TestBLASTBufferQueue", sc, width, height);
+ mBlastBufferQueueAdapter = new BLASTBufferQueue("TestBLASTBufferQueue", sc, width, height,
+ PIXEL_FORMAT_RGBA_8888);
}
void update(const sp<SurfaceControl>& sc, int width, int height) {
- mBlastBufferQueueAdapter->update(sc, width, height);
+ mBlastBufferQueueAdapter->update(sc, width, height, PIXEL_FORMAT_RGBA_8888);
}
void setNextTransaction(Transaction* next) {
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 0e74c63..d69c7ae 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -79,6 +79,7 @@
name: "librenderengine_skia_sources",
srcs: [
"skia/AutoBackendTexture.cpp",
+ "skia/ColorSpaces.cpp",
"skia/SkiaRenderEngine.cpp",
"skia/SkiaGLRenderEngine.cpp",
"skia/debug/CaptureTimer.cpp",
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 2ffb547..c535597 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -20,8 +20,7 @@
#define LOG_TAG "RenderEngine"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <utils/Trace.h>
-
+#include "ColorSpaces.h"
#include "log/log_main.h"
#include "utils/Trace.h"
@@ -29,47 +28,6 @@
namespace renderengine {
namespace skia {
-// Converts an android dataspace to a supported SkColorSpace
-// Supported dataspaces are
-// 1. sRGB
-// 2. Display P3
-// 3. BT2020 PQ
-// 4. BT2020 HLG
-// Unknown primaries are mapped to BT709, and unknown transfer functions
-// are mapped to sRGB.
-static sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) {
- skcms_Matrix3x3 gamut;
- switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
- case HAL_DATASPACE_STANDARD_BT709:
- gamut = SkNamedGamut::kSRGB;
- break;
- case HAL_DATASPACE_STANDARD_BT2020:
- gamut = SkNamedGamut::kRec2020;
- break;
- case HAL_DATASPACE_STANDARD_DCI_P3:
- gamut = SkNamedGamut::kDisplayP3;
- break;
- default:
- ALOGV("Unsupported Gamut: %d, defaulting to sRGB", dataspace);
- gamut = SkNamedGamut::kSRGB;
- break;
- }
-
- switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
- case HAL_DATASPACE_TRANSFER_LINEAR:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
- case HAL_DATASPACE_TRANSFER_SRGB:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
- case HAL_DATASPACE_TRANSFER_ST2084:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
- case HAL_DATASPACE_TRANSFER_HLG:
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
- default:
- ALOGV("Unsupported Gamma: %d, defaulting to sRGB transfer", dataspace);
- return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
- }
-}
-
AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer,
bool isRender) {
ATRACE_CALL();
diff --git a/libs/renderengine/skia/ColorSpaces.cpp b/libs/renderengine/skia/ColorSpaces.cpp
new file mode 100644
index 0000000..ff4d348
--- /dev/null
+++ b/libs/renderengine/skia/ColorSpaces.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 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 "ColorSpaces.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) {
+ skcms_Matrix3x3 gamut;
+ switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+ case HAL_DATASPACE_STANDARD_BT709:
+ gamut = SkNamedGamut::kSRGB;
+ break;
+ case HAL_DATASPACE_STANDARD_BT2020:
+ gamut = SkNamedGamut::kRec2020;
+ break;
+ case HAL_DATASPACE_STANDARD_DCI_P3:
+ gamut = SkNamedGamut::kDisplayP3;
+ break;
+ default:
+ gamut = SkNamedGamut::kSRGB;
+ break;
+ }
+
+ switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+ case HAL_DATASPACE_TRANSFER_LINEAR:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
+ case HAL_DATASPACE_TRANSFER_SRGB:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ case HAL_DATASPACE_TRANSFER_ST2084:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+ case HAL_DATASPACE_TRANSFER_HLG:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
+ default:
+ return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+ }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/ColorSpaces.h b/libs/renderengine/skia/ColorSpaces.h
new file mode 100644
index 0000000..2cbdeb8
--- /dev/null
+++ b/libs/renderengine/skia/ColorSpaces.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 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 "SkColorSpace.h"
+#include "ui/GraphicTypes.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+// Converts an android dataspace to a supported SkColorSpace
+// Supported dataspaces are
+// 1. sRGB
+// 2. Display P3
+// 3. BT2020 PQ
+// 4. BT2020 HLG
+// Unknown primaries are mapped to BT709, and unknown transfer functions
+// are mapped to sRGB.
+sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace);
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index d9495a9..dc04f69 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -30,6 +30,7 @@
#include <SkColorSpace.h>
#include <SkImage.h>
#include <SkImageFilters.h>
+#include <SkRegion.h>
#include <SkShadowUtils.h>
#include <SkSurface.h>
#include <gl/GrGLInterface.h>
@@ -43,6 +44,7 @@
#include <memory>
#include "../gl/GLExtensions.h"
+#include "ColorSpaces.h"
#include "SkBlendMode.h"
#include "SkImageInfo.h"
#include "filters/BlurFilter.h"
@@ -281,6 +283,44 @@
if (args.supportsBackgroundBlur) {
mBlurFilter = new BlurFilter();
}
+ mCapture = std::make_unique<SkiaCapture>();
+}
+
+SkiaGLRenderEngine::~SkiaGLRenderEngine() {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ mRuntimeEffects.clear();
+ mProtectedTextureCache.clear();
+ mTextureCache.clear();
+
+ if (mBlurFilter) {
+ delete mBlurFilter;
+ }
+
+ mCapture = nullptr;
+
+ mGrContext->flushAndSubmit(true);
+ mGrContext->abandonContext();
+
+ if (mProtectedGrContext) {
+ mProtectedGrContext->flushAndSubmit(true);
+ mProtectedGrContext->abandonContext();
+ }
+
+ if (mPlaceholderSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEGLDisplay, mPlaceholderSurface);
+ }
+ if (mProtectedPlaceholderSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(mEGLDisplay, mProtectedPlaceholderSurface);
+ }
+ if (mEGLContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEGLDisplay, mEGLContext);
+ }
+ if (mProtectedEGLContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(mEGLDisplay, mProtectedEGLContext);
+ }
+ eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ eglTerminate(mEGLDisplay);
+ eglReleaseThread();
}
bool SkiaGLRenderEngine::supportsProtectedContent() const {
@@ -298,6 +338,7 @@
useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface;
const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
+
if (success) {
mInProtectedContext = useProtectedContext;
}
@@ -450,6 +491,7 @@
const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
ATRACE_NAME("SkiaGL::drawLayers");
+
std::lock_guard<std::mutex> lock(mRenderingMutex);
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
@@ -488,7 +530,7 @@
if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) {
surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
surfaceTextureRef->setTexture(
- new AutoBackendTexture(mGrContext.get(), buffer->toAHardwareBuffer(), true));
+ new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true));
if (useFramebufferCache) {
ALOGD("Adding to cache");
cache.insert({buffer->getId(), surfaceTextureRef});
@@ -498,10 +540,10 @@
sk_sp<SkSurface> surface =
surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement
? display.outputDataspace
- : ui::Dataspace::SRGB,
- mGrContext.get());
+ : ui::Dataspace::UNKNOWN,
+ grContext.get());
- SkCanvas* canvas = mCapture.tryCapture(surface.get());
+ SkCanvas* canvas = mCapture->tryCapture(surface.get());
if (canvas == nullptr) {
ALOGE("Cannot acquire canvas from Skia.");
return BAD_VALUE;
@@ -510,7 +552,7 @@
canvas->clear(SK_ColorTRANSPARENT);
canvas->save();
- if (mCapture.isCaptureRunning()) {
+ if (mCapture->isCaptureRunning()) {
// Record display settings when capture is running.
std::stringstream displaySettings;
PrintTo(display, &displaySettings);
@@ -546,10 +588,33 @@
canvas->rotate(toDegrees(display.orientation));
canvas->translate(-clipWidth / 2, -clipHeight / 2);
canvas->translate(-display.clip.left, -display.clip.top);
+
+ // TODO: clearRegion was required for SurfaceView when a buffer is not yet available but the
+ // view is still on-screen. The clear region could be re-specified as a black color layer,
+ // however.
+ if (!display.clearRegion.isEmpty()) {
+ size_t numRects = 0;
+ Rect const* rects = display.clearRegion.getArray(&numRects);
+ SkIRect skRects[numRects];
+ for (int i = 0; i < numRects; ++i) {
+ skRects[i] =
+ SkIRect::MakeLTRB(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
+ }
+ SkRegion clearRegion;
+ SkPaint paint;
+ sk_sp<SkShader> shader =
+ SkShaders::Color(SkColor4f{.fR = 0., .fG = 0., .fB = 0., .fA = 1.0},
+ toSkColorSpace(mUseColorManagement ? display.outputDataspace
+ : ui::Dataspace::UNKNOWN));
+ paint.setShader(shader);
+ clearRegion.setRects(skRects, numRects);
+ canvas->drawRegion(clearRegion, paint);
+ }
+
for (const auto& layer : layers) {
canvas->save();
- if (mCapture.isCaptureRunning()) {
+ if (mCapture->isCaptureRunning()) {
// Record the name of the layer if the capture is running.
std::stringstream layerSettings;
PrintTo(*layer, &layerSettings);
@@ -588,6 +653,16 @@
}
}
+ const ui::Dataspace targetDataspace = mUseColorManagement
+ ? (needsLinearEffect(layer->colorTransform, layer->sourceDataspace,
+ display.outputDataspace)
+ // If we need to map to linear space, then mark the source image with the
+ // same colorspace as the destination surface so that Skia's color
+ // management is a no-op.
+ ? display.outputDataspace
+ : layer->sourceDataspace)
+ : ui::Dataspace::UNKNOWN;
+
if (layer->source.buffer.buffer) {
ATRACE_NAME("DrawImage");
const auto& item = layer->source.buffer;
@@ -597,31 +672,18 @@
imageTextureRef = iter->second;
} else {
imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
- imageTextureRef->setTexture(new AutoBackendTexture(mGrContext.get(),
+ imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(),
item.buffer->toAHardwareBuffer(),
false));
- mTextureCache.insert({buffer->getId(), imageTextureRef});
+ mTextureCache.insert({item.buffer->getId(), imageTextureRef});
}
sk_sp<SkImage> image =
- imageTextureRef->getTexture()
- ->makeImage(mUseColorManagement
- ? (needsLinearEffect(layer->colorTransform,
- layer->sourceDataspace,
- display.outputDataspace)
- // If we need to map to linear space,
- // then mark the source image with the
- // same colorspace as the destination
- // surface so that Skia's color
- // management is a no-op.
- ? display.outputDataspace
- : layer->sourceDataspace)
- : ui::Dataspace::SRGB,
- item.isOpaque ? kOpaque_SkAlphaType
- : (item.usePremultipliedAlpha
- ? kPremul_SkAlphaType
- : kUnpremul_SkAlphaType),
- mGrContext.get());
+ imageTextureRef->getTexture()->makeImage(targetDataspace,
+ item.usePremultipliedAlpha
+ ? kPremul_SkAlphaType
+ : kUnpremul_SkAlphaType,
+ grContext.get());
auto texMatrix = getSkM44(item.textureTransform).asM33();
// textureTansform was intended to be passed directly into a shader, so when
@@ -650,11 +712,35 @@
shader = image->makeShader(SkSamplingOptions(), matrix);
}
+ // Handle opaque images - it's a little nonstandard how we do this.
+ // Fundamentally we need to support SurfaceControl.Builder#setOpaque:
+ // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
+ // The important language is that when isOpaque is set, opacity is not sampled from the
+ // alpha channel, but blending may still be supported on a transaction via setAlpha. So,
+ // here's the conundrum:
+ // 1. We can't force the SkImage alpha type to kOpaque_SkAlphaType, because it's treated
+ // as an internal hint - composition is undefined when there are alpha bits present.
+ // 2. We can try to lie about the pixel layout, but that only works for RGBA8888
+ // buffers, i.e., treating them as RGBx8888 instead. But we can't do the same for
+ // RGBA1010102 because RGBx1010102 is not supported as a pixel layout for SkImages. It's
+ // also not clear what to use for F16 either, and lying about the pixel layout is a bit
+ // of a hack anyways.
+ // 3. We can't change the blendmode to src, because while this satisfies the requirement
+ // for ignoring the alpha channel, it doesn't quite satisfy the blending requirement
+ // because src always clobbers the destination content.
+ //
+ // So, what we do here instead is an additive blend mode where we compose the input
+ // image with a solid black. This might need to be reassess if this does not support
+ // FP16 incredibly well, but FP16 end-to-end isn't well supported anyway at the moment.
+ if (item.isOpaque) {
+ shader = SkShaders::Blend(SkBlendMode::kPlus, shader,
+ SkShaders::Color(SkColors::kBlack,
+ toSkColorSpace(targetDataspace)));
+ }
+
paint.setShader(
createRuntimeEffectShader(shader, layer, display,
!item.isOpaque && item.usePremultipliedAlpha));
-
- // Make sure to take into the account the alpha set on the layer.
paint.setAlphaf(layer->alpha);
} else {
ATRACE_NAME("DrawColor");
@@ -662,8 +748,8 @@
sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
.fG = color.g,
.fB = color.b,
- layer->alpha},
- nullptr);
+ .fA = layer->alpha},
+ toSkColorSpace(targetDataspace));
paint.setShader(createRuntimeEffectShader(shader, layer, display,
/* undoPremultipliedAlpha */ false));
}
@@ -671,31 +757,6 @@
sk_sp<SkColorFilter> filter =
SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
- // Handle opaque images - it's a little nonstandard how we do this.
- // Fundamentally we need to support SurfaceControl.Builder#setOpaque:
- // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
- // The important language is that when isOpaque is set, opacity is not sampled from the
- // alpha channel, but blending may still be supported on a transaction via setAlpha. So,
- // here's the conundrum:
- // 1. We can't force the SkImage alpha type to kOpaque_SkAlphaType, because it's treated as
- // an internal hint - composition is undefined when there are alpha bits present.
- // 2. We can try to lie about the pixel layout, but that only works for RGBA8888 buffers,
- // i.e., treating them as RGBx8888 instead. But we can't do the same for RGBA1010102 because
- // RGBx1010102 is not supported as a pixel layout for SkImages. It's also not clear what to
- // use for F16 either, and lying about the pixel layout is a bit of a hack anyways.
- // 3. We can't change the blendmode to src, because while this satisfies the requirement for
- // ignoring the alpha channel, it doesn't quite satisfy the blending requirement because
- // src always clobbers the destination content.
- //
- // So, what we do here instead is an additive blend mode where we compose the input image
- // with a solid black. This might need to be reassess if this does not support FP16
- // incredibly well, but FP16 end-to-end isn't well supported anyway at the moment.
- if (layer->source.buffer.buffer && layer->source.buffer.isOpaque) {
- filter = SkColorFilters::Compose(filter,
- SkColorFilters::Blend(SK_ColorBLACK,
- SkBlendMode::kPlus));
- }
-
paint.setColorFilter(filter);
for (const auto effectRegion : layer->blurRegions) {
@@ -721,7 +782,7 @@
canvas->restore();
}
canvas->restore();
- mCapture.endCapture();
+ mCapture->endCapture();
{
ATRACE_NAME("flush surface");
surface->flush();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 5384ec8..ed62a2a 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -34,9 +34,9 @@
#include "SkImageInfo.h"
#include "SkiaRenderEngine.h"
#include "android-base/macros.h"
+#include "debug/SkiaCapture.h"
#include "filters/BlurFilter.h"
-#include "skia/debug/SkiaCapture.h"
-#include "skia/filters/LinearEffect.h"
+#include "filters/LinearEffect.h"
namespace android {
namespace renderengine {
@@ -48,7 +48,7 @@
SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt,
EGLSurface placeholder, EGLContext protectedContext,
EGLSurface protectedPlaceholder);
- ~SkiaGLRenderEngine() override{};
+ ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex);
void unbindExternalTextureBuffer(uint64_t bufferId) override;
status_t drawLayers(const DisplaySettings& display,
@@ -127,7 +127,7 @@
bool mInProtectedContext = false;
// Object to capture commands send to Skia.
- SkiaCapture mCapture;
+ std::unique_ptr<SkiaCapture> mCapture;
};
} // namespace skia
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 7680649..84af016 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -454,11 +454,18 @@
effectBuilder.child("input") = shader;
- ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace);
- ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
+ if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
+ effectBuilder.uniform("in_rgbToXyz") = mat4();
+ effectBuilder.uniform("in_xyzToRgb") = colorTransform;
+ } else {
+ ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace);
+ ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
- effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ());
- effectBuilder.uniform("in_xyzToRgb") = colorTransform * mat4(outputColorSpace.getXYZtoRGB());
+ effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ());
+ effectBuilder.uniform("in_xyzToRgb") =
+ colorTransform * mat4(outputColorSpace.getXYZtoRGB());
+ }
+
effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
effectBuilder.uniform("in_inputMaxLuminance") =
std::min(maxMasteringLuminance, maxContentLuminance);
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index bcf389b..51c7028 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -14,17 +14,21 @@
cc_test {
name: "librenderengine_test",
- defaults: ["surfaceflinger_defaults"],
+ defaults: ["skia_deps", "surfaceflinger_defaults"],
test_suites: ["device-tests"],
srcs: [
"RenderEngineTest.cpp",
"RenderEngineThreadedTest.cpp",
],
+ include_dirs: [
+ "external/skia/src/gpu",
+ ],
static_libs: [
"libgmock",
"librenderengine",
"librenderengine_mocks",
],
+
shared_libs: [
"libbase",
"libcutils",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 2b8063e..58afe6e 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -22,16 +22,18 @@
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wextra"
-#include <chrono>
-#include <condition_variable>
-#include <fstream>
-
#include <cutils/properties.h>
#include <gtest/gtest.h>
#include <renderengine/RenderEngine.h>
#include <sync/sync.h>
#include <ui/PixelFormat.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <fstream>
+
#include "../gl/GLESRenderEngine.h"
+#include "../skia/SkiaGLRenderEngine.h"
#include "../threaded/RenderEngineThreaded.h"
constexpr int DEFAULT_DISPLAY_WIDTH = 128;
@@ -46,14 +48,26 @@
virtual ~RenderEngineFactory() = default;
virtual std::string name() = 0;
- virtual std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() = 0;
+ virtual renderengine::RenderEngine::RenderEngineType type() = 0;
+ virtual std::unique_ptr<renderengine::RenderEngine> createRenderEngine() = 0;
+ virtual std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() {
+ return nullptr;
+ }
};
class GLESRenderEngineFactory : public RenderEngineFactory {
public:
std::string name() override { return "GLESRenderEngineFactory"; }
- std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+ renderengine::RenderEngine::RenderEngineType type() {
+ return renderengine::RenderEngine::RenderEngineType::GLES;
+ }
+
+ std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
+ return createGLESRenderEngine();
+ }
+
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() {
renderengine::RenderEngineCreationArgs reCreationArgs =
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -63,7 +77,7 @@
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
+ .setRenderEngineType(type())
.build();
return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
}
@@ -73,7 +87,15 @@
public:
std::string name() override { return "GLESCMRenderEngineFactory"; }
- std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+ renderengine::RenderEngine::RenderEngineType type() {
+ return renderengine::RenderEngine::RenderEngineType::GLES;
+ }
+
+ std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
+ return createGLESRenderEngine();
+ }
+
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() override {
renderengine::RenderEngineCreationArgs reCreationArgs =
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -82,7 +104,7 @@
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
+ .setRenderEngineType(type())
.setUseColorManagerment(true)
.build();
return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
@@ -91,9 +113,13 @@
class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
public:
- std::string name() override { return "SkiaGLESRenderEngineFactory"; }
+ std::string name() override { return "SkiaGLRenderEngineFactory"; }
- std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+ renderengine::RenderEngine::RenderEngineType type() {
+ return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
+ }
+
+ std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
renderengine::RenderEngineCreationArgs reCreationArgs =
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -102,17 +128,21 @@
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+ .setRenderEngineType(type())
.build();
- return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+ return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
}
};
class SkiaGLESCMRenderEngineFactory : public RenderEngineFactory {
public:
- std::string name() override { return "SkiaGLESCMRenderEngineFactory"; }
+ std::string name() override { return "SkiaGLCMRenderEngineFactory"; }
- std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+ renderengine::RenderEngine::RenderEngineType type() {
+ return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
+ }
+
+ std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
renderengine::RenderEngineCreationArgs reCreationArgs =
renderengine::RenderEngineCreationArgs::Builder()
.setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -121,10 +151,10 @@
.setPrecacheToneMapperShaderOnly(false)
.setSupportsBackgroundBlur(true)
.setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
- .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+ .setRenderEngineType(type())
.setUseColorManagerment(true)
.build();
- return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+ return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
}
};
@@ -134,7 +164,7 @@
return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
HAL_PIXEL_FORMAT_RGBA_8888, 1,
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
- GRALLOC_USAGE_HW_RENDER,
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
"output");
}
@@ -159,7 +189,9 @@
}
for (uint32_t texName : mTexNames) {
mRE->deleteTextures(1, &texName);
- EXPECT_FALSE(mRE->isTextureNameKnownForTesting(texName));
+ if (mGLESRE != nullptr) {
+ EXPECT_FALSE(mGLESRE->isTextureNameKnownForTesting(texName));
+ }
}
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
@@ -351,12 +383,11 @@
}
void invokeDraw(renderengine::DisplaySettings settings,
- std::vector<const renderengine::LayerSettings*> layers,
- sp<GraphicBuffer> buffer) {
+ std::vector<const renderengine::LayerSettings*> layers) {
base::unique_fd fence;
status_t status =
- mRE->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence);
- mCurrentBuffer = buffer;
+ mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence);
+ mCurrentBuffer = mBuffer;
int fd = fence.release();
if (fd >= 0) {
@@ -365,17 +396,15 @@
}
ASSERT_EQ(NO_ERROR, status);
- if (layers.size() > 0) {
- ASSERT_TRUE(mRE->isFramebufferImageCachedForTesting(buffer->getId()));
+ if (layers.size() > 0 && mGLESRE != nullptr) {
+ ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
}
}
void drawEmptyLayers() {
renderengine::DisplaySettings settings;
std::vector<const renderengine::LayerSettings*> layers;
- // Meaningless buffer since we don't do any drawing
- sp<GraphicBuffer> buffer = new GraphicBuffer();
- invokeDraw(settings, layers, buffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -471,7 +500,12 @@
const renderengine::ShadowSettings& shadow,
const ubyte4& backgroundColor);
- std::unique_ptr<renderengine::gl::GLESRenderEngine> mRE;
+ void initializeRenderEngine();
+
+ std::unique_ptr<renderengine::RenderEngine> mRE;
+ // GLESRenderEngine for testing GLES-specific behavior.
+ // Owened by mRE, but this is downcasted.
+ renderengine::gl::GLESRenderEngine* mGLESRE = nullptr;
// Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
// be freed *after* RenderEngine is destroyed, so that the EGL image is
@@ -483,6 +517,21 @@
std::vector<uint32_t> mTexNames;
};
+void RenderEngineTest::initializeRenderEngine() {
+ const auto& renderEngineFactory = GetParam();
+ if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+ // Only GLESRenderEngine exposes test-only methods. Provide a pointer to the
+ // GLESRenderEngine if we're using it so that we don't need to dynamic_cast
+ // every time.
+ std::unique_ptr<renderengine::gl::GLESRenderEngine> renderEngine =
+ renderEngineFactory->createGLESRenderEngine();
+ mGLESRE = renderEngine.get();
+ mRE = std::move(renderEngine);
+ } else {
+ mRE = renderEngineFactory->createRenderEngine();
+ }
+}
+
struct ColorSourceVariant {
static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
RenderEngineTest* /*fixture*/) {
@@ -509,7 +558,7 @@
static uint8_t getAlphaChannel() {
// The isOpaque bit will override the alpha channel, so this should be
// arbitrary.
- return 10;
+ return 50;
}
};
@@ -563,7 +612,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -606,7 +655,7 @@
layer.alpha = 1.0f;
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -659,7 +708,7 @@
layers.push_back(&layerTwo);
layers.push_back(&layerThree);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -747,7 +796,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -786,7 +835,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -816,7 +865,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -844,7 +893,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
template <typename SourceVariant>
@@ -904,7 +953,7 @@
blurLayer.alpha = 0;
layers.push_back(&blurLayer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
50 /* tolerance */);
@@ -929,7 +978,7 @@
layerOne.alpha = 0.2;
layersFirst.push_back(&layerOne);
- invokeDraw(settings, layersFirst, mBuffer);
+ invokeDraw(settings, layersFirst);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -945,7 +994,7 @@
layerTwo.alpha = 1.0f;
layersSecond.push_back(&layerTwo);
- invokeDraw(settings, layersSecond, mBuffer);
+ invokeDraw(settings, layersSecond);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
@@ -997,7 +1046,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
void RenderEngineTest::fillBufferTextureTransform() {
@@ -1036,7 +1085,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
void RenderEngineTest::fillBufferWithPremultiplyAlpha() {
@@ -1075,7 +1124,7 @@
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() {
@@ -1093,7 +1142,7 @@
// fake layer, without bounds should not render anything
renderengine::LayerSettings layer;
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
void RenderEngineTest::clearRegion() {
@@ -1140,7 +1189,7 @@
casterColor.b / 255.0f, this);
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds,
@@ -1171,7 +1220,7 @@
shadowLayer.shadow = shadow;
layers.push_back(&shadowLayer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
}
INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
@@ -1181,8 +1230,7 @@
std::make_shared<SkiaGLESCMRenderEngineFactory>()));
TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
drawEmptyLayers();
}
@@ -1210,16 +1258,15 @@
std::vector<const renderengine::LayerSettings*> layers;
layers.push_back(&bgLayer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
// Expect to see full opaque pixel (with inverted red from the transform).
- expectBufferColor(Rect(0, 0, 1, 1), 0.f, backgroundColor.g, backgroundColor.b,
+ expectBufferColor(Rect(0, 0, 10, 10), 0.f, backgroundColor.g, backgroundColor.b,
backgroundColor.a);
}
TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1235,8 +1282,7 @@
}
TEST_P(RenderEngineTest, drawLayers_nullOutputFence) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1258,7 +1304,13 @@
TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ // GLES-specific test
+ return;
+ }
+
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1275,355 +1327,264 @@
status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
mCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
- ASSERT_FALSE(mRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+ ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillRedBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillGreenBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBlueBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillRedTransparentBuffer<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferPhysicalOffset<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate0<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate90<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate180<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate270<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferLayerTransform<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferColorTransform<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferWithRoundedCorners<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferAndBlurBackground<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
overlayCorners<ColorSourceVariant>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillGreenBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBlueBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillRedTransparentBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferPhysicalOffset<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate0<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate90<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate180<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate270<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferColorTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
-TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
+ initializeRenderEngine();
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillGreenBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBlueBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillRedTransparentBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferPhysicalOffset<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate0<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate90<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate180<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferCheckersRotate270<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferColorTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
}
TEST_P(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferTextureTransform();
}
TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferWithPremultiplyAlpha();
}
TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
fillBufferWithoutPremultiplyAlpha();
}
TEST_P(RenderEngineTest, drawLayers_clearRegion) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
-
+ initializeRenderEngine();
clearRegion();
}
TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ // GLES-specific test
+ return;
+ }
+
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1637,26 +1598,32 @@
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layers.push_back(&layer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
uint64_t bufferId = layer.source.buffer.buffer->getId();
- EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
+ EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- mRE->unbindExternalTextureBufferForTesting(bufferId);
+ mGLESRE->unbindExternalTextureBufferForTesting(bufferId);
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
[&]() REQUIRES(barrier->mutex) {
return barrier->isOpen;
}));
- EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
+ EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
EXPECT_EQ(NO_ERROR, barrier->result);
}
TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) {
const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ // GLES-specific test
+ return;
+ }
+
+ initializeRenderEngine();
std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- mRE->cacheExternalTextureBufferForTesting(nullptr);
+ mGLESRE->cacheExternalTextureBufferForTesting(nullptr);
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
[&]() REQUIRES(barrier->mutex) {
@@ -1668,12 +1635,18 @@
TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) {
const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ // GLES-specific test
+ return;
+ }
+
+ initializeRenderEngine();
sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
uint64_t bufferId = buf->getId();
std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
- mRE->cacheExternalTextureBufferForTesting(buf);
+ mGLESRE->cacheExternalTextureBufferForTesting(buf);
{
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
@@ -1682,8 +1655,8 @@
}));
EXPECT_EQ(NO_ERROR, barrier->result);
}
- EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
- barrier = mRE->unbindExternalTextureBufferForTesting(bufferId);
+ EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
+ barrier = mGLESRE->unbindExternalTextureBufferForTesting(bufferId);
{
std::lock_guard<std::mutex> lock(barrier->mutex);
ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
@@ -1692,12 +1665,11 @@
}));
EXPECT_EQ(NO_ERROR, barrier->result);
}
- EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
+ EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
const ubyte4 backgroundColor(255, 255, 255, 255);
const float shadowLength = 5.0f;
@@ -1712,8 +1684,7 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1732,8 +1703,7 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1753,8 +1723,7 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1775,8 +1744,7 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1798,8 +1766,7 @@
}
TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
const ubyte4 casterColor(255, 0, 0, 255);
const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1827,7 +1794,13 @@
TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ // GLES-specific test
+ return;
+ }
+
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -1859,7 +1832,13 @@
TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory) {
const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+
+ if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+ // GLES-specific test
+ return;
+ }
+
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1883,20 +1862,19 @@
uint64_t bufferId = layer.source.buffer.buffer->getId();
uint32_t texName = layer.source.buffer.textureName;
- EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
- EXPECT_EQ(bufferId, mRE->getBufferIdForTextureNameForTesting(texName));
+ EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(bufferId, mGLESRE->getBufferIdForTextureNameForTesting(texName));
EXPECT_TRUE(mRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL));
// Now check that our view of memory is good.
- EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
- EXPECT_EQ(std::nullopt, mRE->getBufferIdForTextureNameForTesting(bufferId));
- EXPECT_TRUE(mRE->isTextureNameKnownForTesting(texName));
+ EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
+ EXPECT_EQ(std::nullopt, mGLESRE->getBufferIdForTextureNameForTesting(bufferId));
+ EXPECT_TRUE(mGLESRE->isTextureNameKnownForTesting(texName));
}
TEST_P(RenderEngineTest, testRoundedCornersCrop) {
- const auto& renderEngineFactory = GetParam();
- mRE = renderEngineFactory->createRenderEngine();
+ initializeRenderEngine();
renderengine::DisplaySettings settings;
settings.physicalDisplay = fullscreenRect();
@@ -1931,7 +1909,7 @@
layers.push_back(&greenLayer);
- invokeDraw(settings, layers, mBuffer);
+ invokeDraw(settings, layers);
// Corners should be ignored...
// Screen size: width is 128, height is 256.
diff --git a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
index cd8e19c..d76f039 100644
--- a/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTracerTest.cpp
@@ -56,7 +56,6 @@
}
void SetUp() override {
- SKIP_IF_BPF_NOT_SUPPORTED;
bpf::setrlimitForTest();
mGpuMem = std::make_shared<GpuMem>();
@@ -122,7 +121,6 @@
}
TEST_F(GpuMemTracerTest, traceInitialCountersAfterGpuMemInitialize) {
- SKIP_IF_BPF_NOT_SUPPORTED;
ASSERT_RESULT_OK(mTestMap.writeValue(TEST_GLOBAL_KEY, TEST_GLOBAL_VAL, BPF_ANY));
ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_1, TEST_PROC_VAL_1, BPF_ANY));
ASSERT_RESULT_OK(mTestMap.writeValue(TEST_PROC_KEY_2, TEST_PROC_VAL_2, BPF_ANY));
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index cdc74f3..b3558c6 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -314,6 +314,14 @@
return first->getToken() == second->getToken();
}
+static bool haveSameApplicationToken(const InputWindowInfo* first, const InputWindowInfo* second) {
+ if (first == nullptr || second == nullptr) {
+ return false;
+ }
+ return first->applicationInfo.token != nullptr &&
+ first->applicationInfo.token == second->applicationInfo.token;
+}
+
static bool isStaleEvent(nsecs_t currentTime, const EventEntry& entry) {
return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
}
@@ -2422,8 +2430,8 @@
break; // All future windows are below us. Exit early.
}
const InputWindowInfo* otherInfo = otherHandle->getInfo();
- if (canBeObscuredBy(windowHandle, otherHandle) &&
- windowInfo->ownerUid != otherInfo->ownerUid && otherInfo->frameContainsPoint(x, y)) {
+ if (canBeObscuredBy(windowHandle, otherHandle) && otherInfo->frameContainsPoint(x, y) &&
+ !haveSameApplicationToken(windowInfo, otherInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
info.debugInfo.push_back(
dumpWindowForTouchOcclusion(otherInfo, /* isTouchedWindow */ false));
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index ac4669c..28f29e0 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -206,7 +206,7 @@
}
bool JoystickInputMapper::haveAxis(int32_t axisId) {
- for (const std::pair<int32_t, Axis>& pair : mAxes) {
+ for (const std::pair<const int32_t, Axis>& pair : mAxes) {
const Axis& axis = pair.second;
if (axis.axisInfo.axis == axisId ||
(axis.axisInfo.mode == AxisInfo::MODE_SPLIT && axis.axisInfo.highAxis == axisId)) {
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 424a8b3..39ae2fd 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -176,7 +176,14 @@
if (!holes.isEmpty()) {
targetSettings.clearRegion.orSelf(holes);
}
- return std::nullopt;
+
+ if (mSidebandStream != nullptr) {
+ // For surfaceview of tv sideband, there is no activeBuffer
+ // in bufferqueue, we need return LayerSettings.
+ return result;
+ } else {
+ return std::nullopt;
+ }
}
bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
(isSecure() && !targetSettings.isSecure);
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index c994434..17d1f3b 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -95,35 +95,46 @@
}
std::string jankTypeBitmaskToString(int32_t jankType) {
- // TODO(b/175843808): Make this a switch case if jankType becomes an enum class
- std::vector<std::string> janks;
if (jankType == JankType::None) {
return "None";
}
+
+ std::vector<std::string> janks;
if (jankType & JankType::DisplayHAL) {
janks.emplace_back("Display HAL");
+ jankType &= ~JankType::DisplayHAL;
}
if (jankType & JankType::SurfaceFlingerCpuDeadlineMissed) {
janks.emplace_back("SurfaceFlinger CPU Deadline Missed");
+ jankType &= ~JankType::SurfaceFlingerCpuDeadlineMissed;
}
if (jankType & JankType::SurfaceFlingerGpuDeadlineMissed) {
janks.emplace_back("SurfaceFlinger GPU Deadline Missed");
+ jankType &= ~JankType::SurfaceFlingerGpuDeadlineMissed;
}
if (jankType & JankType::AppDeadlineMissed) {
janks.emplace_back("App Deadline Missed");
+ jankType &= ~JankType::AppDeadlineMissed;
}
if (jankType & JankType::PredictionError) {
janks.emplace_back("Prediction Error");
+ jankType &= ~JankType::PredictionError;
}
if (jankType & JankType::SurfaceFlingerScheduling) {
janks.emplace_back("SurfaceFlinger Scheduling");
+ jankType &= ~JankType::SurfaceFlingerScheduling;
}
if (jankType & JankType::BufferStuffing) {
janks.emplace_back("Buffer Stuffing");
+ jankType &= ~JankType::BufferStuffing;
}
if (jankType & JankType::Unknown) {
janks.emplace_back("Unknown jank");
+ jankType &= ~JankType::Unknown;
}
+
+ // jankType should be 0 if all types of jank were checked for.
+ LOG_ALWAYS_FATAL_IF(jankType != 0, "Unrecognized jank type value 0x%x", jankType);
return std::accumulate(janks.begin(), janks.end(), std::string(),
[](const std::string& l, const std::string& r) {
return l.empty() ? r : l + ", " + r;
@@ -192,27 +203,48 @@
}
}
-FrameTimelineEvent::JankType jankTypeBitmaskToProto(int32_t jankType) {
- // TODO(b/175843808): Either make the proto a bitmask or jankType an enum class
- switch (jankType) {
- case JankType::None:
- return FrameTimelineEvent::JANK_NONE;
- case JankType::DisplayHAL:
- return FrameTimelineEvent::JANK_DISPLAY_HAL;
- case JankType::SurfaceFlingerCpuDeadlineMissed:
- case JankType::SurfaceFlingerGpuDeadlineMissed:
- return FrameTimelineEvent::JANK_SF_DEADLINE_MISSED;
- case JankType::AppDeadlineMissed:
- case JankType::PredictionError:
- return FrameTimelineEvent::JANK_APP_DEADLINE_MISSED;
- case JankType::SurfaceFlingerScheduling:
- return FrameTimelineEvent::JANK_SF_SCHEDULING;
- case JankType::BufferStuffing:
- return FrameTimelineEvent::JANK_BUFFER_STUFFING;
- default:
- // TODO(b/175843808): Remove default if JankType becomes an enum class
- return FrameTimelineEvent::JANK_UNKNOWN;
+int32_t jankTypeBitmaskToProto(int32_t jankType) {
+ if (jankType == JankType::None) {
+ return FrameTimelineEvent::JANK_NONE;
}
+
+ int32_t protoJank = 0;
+ if (jankType & JankType::DisplayHAL) {
+ protoJank |= FrameTimelineEvent::JANK_DISPLAY_HAL;
+ jankType &= ~JankType::DisplayHAL;
+ }
+ if (jankType & JankType::SurfaceFlingerCpuDeadlineMissed) {
+ protoJank |= FrameTimelineEvent::JANK_SF_CPU_DEADLINE_MISSED;
+ jankType &= ~JankType::SurfaceFlingerCpuDeadlineMissed;
+ }
+ if (jankType & JankType::SurfaceFlingerGpuDeadlineMissed) {
+ protoJank |= FrameTimelineEvent::JANK_SF_GPU_DEADLINE_MISSED;
+ jankType &= ~JankType::SurfaceFlingerGpuDeadlineMissed;
+ }
+ if (jankType & JankType::AppDeadlineMissed) {
+ protoJank |= FrameTimelineEvent::JANK_APP_DEADLINE_MISSED;
+ jankType &= ~JankType::AppDeadlineMissed;
+ }
+ if (jankType & JankType::PredictionError) {
+ protoJank |= FrameTimelineEvent::JANK_PREDICTION_ERROR;
+ jankType &= ~JankType::PredictionError;
+ }
+ if (jankType & JankType::SurfaceFlingerScheduling) {
+ protoJank |= FrameTimelineEvent::JANK_SF_SCHEDULING;
+ jankType &= ~JankType::SurfaceFlingerScheduling;
+ }
+ if (jankType & JankType::BufferStuffing) {
+ protoJank |= FrameTimelineEvent::JANK_BUFFER_STUFFING;
+ jankType &= ~JankType::BufferStuffing;
+ }
+ if (jankType & JankType::Unknown) {
+ protoJank |= FrameTimelineEvent::JANK_UNKNOWN;
+ jankType &= ~JankType::Unknown;
+ }
+
+ // jankType should be 0 if all types of jank were checked for.
+ LOG_ALWAYS_FATAL_IF(jankType != 0, "Unrecognized jank type value 0x%x", jankType);
+ return protoJank;
}
// Returns the smallest timestamp from the set of predictions and actuals.
@@ -449,22 +481,22 @@
void SurfaceFrame::trace(int64_t displayFrameToken) {
using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource;
- {
+
+ int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+ bool missingToken = false;
+ // Expected timeline start
+ FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::lock_guard<std::mutex> lock(mMutex);
if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str());
+ missingToken = true;
return;
} else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) {
ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken",
mLayerName.c_str());
+ missingToken = true;
return;
}
- }
-
- int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
- // Expected timeline start
- FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
- std::lock_guard<std::mutex> lock(mMutex);
auto packet = ctx.NewTracePacket();
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
packet->set_timestamp(static_cast<uint64_t>(mPredictions.startTime));
@@ -480,6 +512,13 @@
expectedSurfaceFrameStartEvent->set_pid(mOwnerPid);
expectedSurfaceFrameStartEvent->set_layer_name(mDebugName);
});
+
+ if (missingToken) {
+ // If one packet can't be traced because of missing token, then no packets can be traced.
+ // Exit early in this case.
+ return;
+ }
+
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
std::lock_guard<std::mutex> lock(mMutex);
@@ -782,15 +821,16 @@
}
void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
- if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
- ALOGD("Cannot trace DisplayFrame with invalid token");
- return;
- }
-
int64_t expectedTimelineCookie = mTraceCookieCounter.getCookieForTracing();
+ bool missingToken = false;
// Expected timeline start
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
+ if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) {
+ ALOGD("Cannot trace DisplayFrame with invalid token");
+ missingToken = true;
+ return;
+ }
packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC);
packet->set_timestamp(static_cast<uint64_t>(mSurfaceFlingerPredictions.startTime));
@@ -802,6 +842,13 @@
expectedDisplayFrameStartEvent->set_token(mToken);
expectedDisplayFrameStartEvent->set_pid(surfaceFlingerPid);
});
+
+ if (missingToken) {
+ // If one packet can't be traced because of missing token, then no packets can be traced.
+ // Exit early in this case.
+ return;
+ }
+
// Expected timeline end
FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) {
auto packet = ctx.NewTracePacket();
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 0fa71f1..4324855 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -54,7 +54,7 @@
break;
case LayerUpdateType::SetFrameRate:
case LayerUpdateType::Buffer:
- FrameTimeData frameTime = {.presetTime = lastPresentTime,
+ FrameTimeData frameTime = {.presentTime = lastPresentTime,
.queueTime = mLastUpdatedTime,
.pendingConfigChange = pendingConfigChange};
mFrameTimes.push_back(frameTime);
@@ -74,7 +74,7 @@
bool LayerInfo::isFrequent(nsecs_t now) const {
// 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) {
+ if (mFrameTimes.size() < kFrequentLayerWindowSize) {
return true;
}
@@ -87,14 +87,14 @@
}
const auto numFrames = std::distance(it, mFrameTimes.end());
- if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) {
+ if (numFrames < kFrequentLayerWindowSize) {
return false;
}
// Layer is considered frequent if the average frame rate is higher than the threshold
const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
return Fps::fromPeriodNsecs(totalTime / (numFrames - 1))
- .greaterThanOrEqualWithMargin(MIN_FPS_FOR_FREQUENT_LAYER);
+ .greaterThanOrEqualWithMargin(kMinFpsForFrequentLayer);
}
bool LayerInfo::isAnimating(nsecs_t now) const {
@@ -124,32 +124,21 @@
}
std::optional<nsecs_t> LayerInfo::calculateAverageFrameTime() const {
- nsecs_t totalPresentTimeDeltas = 0;
- nsecs_t totalQueueTimeDeltas = 0;
- bool missingPresentTime = false;
- int numFrames = 0;
- for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
- // Ignore frames captured during a config change
- if (it->pendingConfigChange || (it + 1)->pendingConfigChange) {
- return std::nullopt;
- }
+ // Ignore frames captured during a config change
+ const bool isDuringConfigChange =
+ std::any_of(mFrameTimes.begin(), mFrameTimes.end(),
+ [](auto frame) { return frame.pendingConfigChange; });
+ if (isDuringConfigChange) {
+ return std::nullopt;
+ }
- totalQueueTimeDeltas +=
- std::max(((it + 1)->queueTime - it->queueTime), kMinPeriodBetweenFrames);
- numFrames++;
-
- if (!missingPresentTime && (it->presetTime == 0 || (it + 1)->presetTime == 0)) {
- missingPresentTime = true;
- // If there are no presentation timestamps and we haven't calculated
- // one in the past then we can't calculate the refresh rate
- if (!mLastRefreshRate.reported.isValid()) {
- return std::nullopt;
- }
- continue;
- }
-
- totalPresentTimeDeltas +=
- std::max(((it + 1)->presetTime - it->presetTime), kMinPeriodBetweenFrames);
+ const bool isMissingPresentTime =
+ std::any_of(mFrameTimes.begin(), mFrameTimes.end(),
+ [](auto frame) { return frame.presentTime == 0; });
+ if (isMissingPresentTime && !mLastRefreshRate.reported.isValid()) {
+ // If there are no presentation timestamps and we haven't calculated
+ // one in the past then we can't calculate the refresh rate
+ return std::nullopt;
}
// Calculate the average frame time based on presentation timestamps. If those
@@ -160,9 +149,35 @@
// presentation timestamps we look at the queue time to see if the current refresh rate still
// matches the content.
- const auto averageFrameTime =
- static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) /
- numFrames;
+ auto getFrameTime = isMissingPresentTime ? [](FrameTimeData data) { return data.queueTime; }
+ : [](FrameTimeData data) { return data.presentTime; };
+
+ nsecs_t totalDeltas = 0;
+ int numDeltas = 0;
+ auto prevFrame = mFrameTimes.begin();
+ for (auto it = mFrameTimes.begin() + 1; it != mFrameTimes.end(); ++it) {
+ const auto currDelta = getFrameTime(*it) - getFrameTime(*prevFrame);
+ if (currDelta < kMinPeriodBetweenFrames) {
+ // Skip this frame, but count the delta into the next frame
+ continue;
+ }
+
+ prevFrame = it;
+
+ if (currDelta > kMaxPeriodBetweenFrames) {
+ // Skip this frame and the current delta.
+ continue;
+ }
+
+ totalDeltas += currDelta;
+ numDeltas++;
+ }
+
+ if (numDeltas == 0) {
+ return std::nullopt;
+ }
+
+ const auto averageFrameTime = static_cast<double>(totalDeltas) / static_cast<double>(numDeltas);
return static_cast<nsecs_t>(averageFrameTime);
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 427cc9e..e32ba09 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -49,12 +49,13 @@
// Layer is considered frequent if the earliest value in the window of most recent present times
// is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
// favor of a low refresh rate.
- static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
- static constexpr Fps MIN_FPS_FOR_FREQUENT_LAYER{10.0f};
- static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS =
- std::chrono::nanoseconds(MIN_FPS_FOR_FREQUENT_LAYER.getPeriodNsecs()) + 1ms;
+ static constexpr size_t kFrequentLayerWindowSize = 3;
+ static constexpr Fps kMinFpsForFrequentLayer{10.0f};
+ static constexpr auto kMaxPeriodForFrequentLayerNs =
+ std::chrono::nanoseconds(kMinFpsForFrequentLayer.getPeriodNsecs()) + 1ms;
friend class LayerHistoryTest;
+ friend class LayerInfoTest;
public:
// Holds information about the layer vote
@@ -121,7 +122,7 @@
private:
// Used to store the layer timestamps
struct FrameTimeData {
- nsecs_t presetTime; // desiredPresentTime, if provided
+ nsecs_t presentTime; // desiredPresentTime, if provided
nsecs_t queueTime; // buffer queue time
bool pendingConfigChange;
};
@@ -196,6 +197,10 @@
// Used for sanitizing the heuristic data. If two frames are less than
// this period apart from each other they'll be considered as duplicates.
static constexpr nsecs_t kMinPeriodBetweenFrames = Fps(120.f).getPeriodNsecs();
+ // Used for sanitizing the heuristic data. If two frames are more than
+ // this period apart from each other, the interval between them won't be
+ // taken into account when calculating average frame rate.
+ static constexpr nsecs_t kMaxPeriodBetweenFrames = kMinFpsForFrequentLayer.getPeriodNsecs();
LayerHistory::LayerVoteType mDefaultVote;
LayerVote mLayerVote;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 10bdf94..d91b542 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -276,6 +276,7 @@
const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER");
const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
+const String16 sUseBackgroundBlur("android.permission.USE_BACKGROUND_BLUR");
const String16 sDump("android.permission.DUMP");
const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
@@ -333,6 +334,10 @@
PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid);
}
+bool originalCallerCanUseBlurs(int originPid, int originUid) {
+ return PermissionCache::checkPermission(sUseBackgroundBlur, originPid, originUid);
+}
+
SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
@@ -1913,17 +1918,19 @@
bool SurfaceFlinger::handleMessageTransaction() {
ATRACE_CALL();
-
- if (getTransactionFlags(eTransactionFlushNeeded)) {
- flushPendingTransactionQueues();
- flushTransactionQueue();
- }
uint32_t transactionFlags = peekTransactionFlags();
+
+ bool flushedATransaction = flushTransactionQueues();
+
bool runHandleTransaction =
- ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal;
+ (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) ||
+ flushedATransaction ||
+ mForceTraversal;
if (runHandleTransaction) {
handleTransaction(eTransactionMask);
+ } else {
+ getTransactionFlags(eTransactionFlushNeeded);
}
if (transactionFlushNeeded()) {
@@ -2828,6 +2835,7 @@
});
}
+ commitInputWindowCommands();
commitTransaction();
}
@@ -2868,6 +2876,11 @@
: nullptr);
}
+void SurfaceFlinger::commitInputWindowCommands() {
+ mInputWindowCommands.merge(mPendingInputWindowCommands);
+ mPendingInputWindowCommands.clear();
+}
+
void SurfaceFlinger::updateCursorAsync() {
compositionengine::CompositionRefreshArgs refreshArgs;
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
@@ -3229,55 +3242,55 @@
mForceTraversal = true;
}
-void SurfaceFlinger::flushPendingTransactionQueues() {
+bool SurfaceFlinger::flushTransactionQueues() {
// to prevent onHandleDestroyed from being called while the lock is held,
// we must keep a copy of the transactions (specifically the composer
// states) around outside the scope of the lock
std::vector<const TransactionState> transactions;
+ bool flushedATransaction = false;
{
- Mutex::Autolock _l(mQueueLock);
+ Mutex::Autolock _l(mStateLock);
- auto it = mPendingTransactionQueues.begin();
- while (it != mPendingTransactionQueues.end()) {
+ auto it = mTransactionQueues.begin();
+ while (it != mTransactionQueues.end()) {
auto& [applyToken, transactionQueue] = *it;
while (!transactionQueue.empty()) {
const auto& transaction = transactionQueue.front();
if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
transaction.states)) {
+ setTransactionFlags(eTransactionFlushNeeded);
break;
}
transactions.push_back(transaction);
+ applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+ transaction.displays, transaction.flags,
+ mPendingInputWindowCommands, transaction.desiredPresentTime,
+ transaction.isAutoTimestamp, transaction.buffer,
+ transaction.postTime, transaction.privileged,
+ transaction.hasListenerCallbacks,
+ transaction.listenerCallbacks, transaction.originPid,
+ transaction.originUid, transaction.id, /*isMainThread*/ true);
transactionQueue.pop();
+ flushedATransaction = true;
}
if (transactionQueue.empty()) {
- it = mPendingTransactionQueues.erase(it);
- mTransactionQueueCV.broadcast();
+ it = mTransactionQueues.erase(it);
+ mTransactionCV.broadcast();
} else {
it = std::next(it, 1);
}
}
}
-
- {
- Mutex::Autolock _l(mStateLock);
- for (const auto& transaction : transactions) {
- applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
- transaction.displays, transaction.flags, mInputWindowCommands,
- transaction.desiredPresentTime, transaction.isAutoTimestamp,
- transaction.buffer, transaction.postTime, transaction.privileged,
- transaction.hasListenerCallbacks, transaction.listenerCallbacks,
- transaction.originPid, transaction.originUid, transaction.id);
- }
- }
+ return flushedATransaction;
}
bool SurfaceFlinger::transactionFlushNeeded() {
- Mutex::Autolock _l(mQueueLock);
- return !mPendingTransactionQueues.empty();
+ return !mTransactionQueues.empty();
}
+
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states,
bool updateTransactionCounters) {
@@ -3299,8 +3312,6 @@
if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
ready = false;
}
-
- Mutex::Autolock _l(mStateLock);
sp<Layer> layer = nullptr;
if (s.surface) {
layer = fromHandleLocked(s.surface).promote();
@@ -3313,8 +3324,9 @@
ready = false;
}
if (updateTransactionCounters) {
- // See BufferStateLayer::mPendingBufferTransactions
- if (layer) layer->incrementPendingBufferCount();
+ // See BufferStateLayer::mPendingBufferTransactions
+ if (layer) layer->incrementPendingBufferCount();
+
}
}
return ready;
@@ -3331,153 +3343,90 @@
const int64_t postTime = systemTime();
bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
- {
- Mutex::Autolock _l(mQueueLock);
- // If its TransactionQueue already has a pending TransactionState or if it is pending
- auto itr = mPendingTransactionQueues.find(applyToken);
- // if this is an animation frame, wait until prior animation frame has
- // been applied by SF
- if (flags & eAnimation) {
- while (itr != mPendingTransactionQueues.end() ||
- (!mTransactionQueue.empty() && mAnimTransactionPending)) {
- status_t err = mTransactionQueueCV.waitRelative(mQueueLock, s2ns(5));
- if (CC_UNLIKELY(err != NO_ERROR)) {
- ALOGW_IF(err == TIMED_OUT,
- "setTransactionState timed out "
- "waiting for animation frame to apply");
- break;
- }
- itr = mPendingTransactionQueues.find(applyToken);
+ Mutex::Autolock _l(mStateLock);
+
+ // If its TransactionQueue already has a pending TransactionState or if it is pending
+ auto itr = mTransactionQueues.find(applyToken);
+ // if this is an animation frame, wait until prior animation frame has
+ // been applied by SF
+ if (flags & eAnimation) {
+ while (itr != mTransactionQueues.end()) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ ALOGW_IF(err == TIMED_OUT,
+ "setTransactionState timed out "
+ "waiting for animation frame to apply");
+ break;
}
+ itr = mTransactionQueues.find(applyToken);
}
-
- const bool pendingTransactions = itr != mPendingTransactionQueues.end();
- // Expected present time is computed and cached on invalidate, so it may be stale.
- if (!pendingTransactions) {
- const auto now = systemTime();
- const bool nextVsyncPending = now < mExpectedPresentTime.load();
- const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
- mExpectedPresentTime = calculateExpectedPresentTime(stats);
- // The transaction might arrive just before the next vsync but after
- // invalidate was called. In that case we need to get the next vsync
- // afterwards.
- if (nextVsyncPending) {
- mExpectedPresentTime += stats.vsyncPeriod;
- }
- }
-
- // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
- if (flags & eEarlyWakeup) {
- ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
- }
-
- if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
- ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
- flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
- }
-
- IPCThreadState* ipc = IPCThreadState::self();
- const int originPid = ipc->getCallingPid();
- const int originUid = ipc->getCallingUid();
-
- // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
- // if the transaction contains a buffer.
- if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states,
- true) ||
- pendingTransactions) {
- mPendingTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays,
- flags, inputWindowCommands,
- desiredPresentTime, isAutoTimestamp,
- uncacheBuffer, postTime, privileged,
- hasListenerCallbacks, listenerCallbacks,
- originPid, originUid, transactionId);
-
- setTransactionFlags(eTransactionFlushNeeded);
- return NO_ERROR;
- }
-
- mTransactionQueue.emplace_back(frameTimelineVsyncId, states, displays, flags,
- inputWindowCommands, desiredPresentTime, isAutoTimestamp,
- uncacheBuffer, postTime, privileged, hasListenerCallbacks,
- listenerCallbacks, originPid, originUid, transactionId);
}
- const auto schedule = [](uint32_t flags) {
- if (flags & eEarlyWakeup) return TransactionSchedule::Early;
- if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
- if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
- return TransactionSchedule::Late;
- }(flags);
- setTransactionFlags(eTransactionFlushNeeded, schedule);
+ const bool pendingTransactions = itr != mTransactionQueues.end();
+ // Expected present time is computed and cached on invalidate, so it may be stale.
+ if (!pendingTransactions) {
+ const auto now = systemTime();
+ const bool nextVsyncPending = now < mExpectedPresentTime.load();
+ const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
+ mExpectedPresentTime = calculateExpectedPresentTime(stats);
+ // The transaction might arrive just before the next vsync but after
+ // invalidate was called. In that case we need to get the next vsync
+ // afterwards.
+ if (nextVsyncPending) {
+ mExpectedPresentTime += stats.vsyncPeriod;
+ }
+ }
- // if this is a synchronous transaction, wait for it to take effect
- // before returning.
- const bool synchronous = flags & eSynchronous;
- const bool syncInput = inputWindowCommands.syncInputWindows;
- if (!synchronous && !syncInput) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int originPid = ipc->getCallingPid();
+ const int originUid = ipc->getCallingUid();
+
+ // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
+ // if the transaction contains a buffer.
+ if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states, true) ||
+ pendingTransactions) {
+ mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags,
+ desiredPresentTime, isAutoTimestamp, uncacheBuffer,
+ postTime, privileged, hasListenerCallbacks,
+ listenerCallbacks, originPid, originUid,
+ transactionId);
+ setTransactionFlags(eTransactionFlushNeeded);
return NO_ERROR;
}
- // Handle synchronous cases.
- {
- Mutex::Autolock _l(mStateLock);
- if (synchronous) {
- mTransactionPending = true;
- }
- if (syncInput) {
- mPendingSyncInputWindows = true;
- }
+ applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands,
+ desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged,
+ hasListenerCallbacks, listenerCallbacks, originPid, originUid,
+ transactionId, /*isMainThread*/ false);
+ return NO_ERROR;
+}
- // applyTransactionState can be called by either the main SF thread or by
- // another process through setTransactionState. While a given process may wish
- // to wait on synchronous transactions, the main SF thread should never
- // be blocked. Therefore, we only wait if isMainThread is false.
- while (mTransactionPending || mPendingSyncInputWindows) {
+void SurfaceFlinger::applyTransactionState(
+ int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags,
+ const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
+ bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime,
+ bool privileged, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, int originPid, int originUid,
+ uint64_t transactionId, bool isMainThread) {
+ uint32_t transactionFlags = 0;
+
+ if (flags & eAnimation) {
+ // For window updates that are part of an animation we must wait for
+ // previous animation "frames" to be handled.
+ while (!isMainThread && mAnimTransactionPending) {
status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
if (CC_UNLIKELY(err != NO_ERROR)) {
// just in case something goes wrong in SF, return to the
- // called after a few seconds.
- ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
- mTransactionPending = false;
- mPendingSyncInputWindows = false;
+ // caller after a few seconds.
+ ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
+ "waiting for previous animation frame");
+ mAnimTransactionPending = false;
break;
}
}
}
- return NO_ERROR;
-}
-
-void SurfaceFlinger::flushTransactionQueue() {
- std::vector<TransactionState> transactionQueue;
- {
- Mutex::Autolock _l(mQueueLock);
- if (!mTransactionQueue.empty()) {
- transactionQueue.swap(mTransactionQueue);
- }
- mTransactionQueueCV.broadcast();
- }
-
- Mutex::Autolock _l(mStateLock);
- for (const auto& t : transactionQueue) {
- applyTransactionState(t.frameTimelineVsyncId, t.states, t.displays, t.flags,
- t.inputWindowCommands, t.desiredPresentTime, t.isAutoTimestamp,
- t.buffer, t.postTime, t.privileged, t.hasListenerCallbacks,
- t.listenerCallbacks, t.originPid, t.originUid, t.id);
- }
-}
-
-void SurfaceFlinger::applyTransactionState(int64_t frameTimelineVsyncId,
- const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags,
- const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime, bool isAutoTimestamp,
- const client_cache_t& uncacheBuffer,
- const int64_t postTime, bool privileged,
- bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPid, int originUid, uint64_t transactionId) {
- uint32_t transactionFlags = 0;
for (const DisplayState& display : displays) {
transactionFlags |= setDisplayStateLocked(display);
@@ -3494,9 +3443,10 @@
std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces;
uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- clientStateFlags |= setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime,
- isAutoTimestamp, postTime, privileged,
- listenerCallbacksWithSurfaces);
+ clientStateFlags |=
+ setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime,
+ isAutoTimestamp, postTime, privileged,
+ listenerCallbacksWithSurfaces, originPid, originUid);
if ((flags & eAnimation) && state.state.surface) {
if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) {
mScheduler->recordLayerHistory(layer.get(),
@@ -3536,25 +3486,80 @@
transactionFlags = eTransactionNeeded;
}
+ // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
+ // so we don't have to wake up again next frame to preform an uneeded traversal.
+ if (isMainThread && (transactionFlags & eTraversalNeeded)) {
+ transactionFlags = transactionFlags & (~eTraversalNeeded);
+ mForceTraversal = true;
+ }
+
+ const auto schedule = [](uint32_t flags) {
+ if (flags & eEarlyWakeup) return TransactionSchedule::Early;
+ if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
+ if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
+ return TransactionSchedule::Late;
+ }(flags);
+
if (transactionFlags) {
if (mInterceptor->isEnabled()) {
mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
originPid, originUid, transactionId);
}
- // We are on the main thread, we are about to preform a traversal. Clear the traversal bit
- // so we don't have to wake up again next frame to preform an unnecessary traversal.
- if (transactionFlags & eTraversalNeeded) {
- transactionFlags = transactionFlags & (~eTraversalNeeded);
- mForceTraversal = true;
+ // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
+ if (flags & eEarlyWakeup) {
+ ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
}
- if (transactionFlags) {
- setTransactionFlags(transactionFlags);
+
+ if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
+ ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
+ flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
}
+ // this triggers the transaction
+ setTransactionFlags(transactionFlags, schedule);
+
if (flags & eAnimation) {
mAnimTransactionPending = true;
}
+
+ // if this is a synchronous transaction, wait for it to take effect
+ // before returning.
+ const bool synchronous = flags & eSynchronous;
+ const bool syncInput = inputWindowCommands.syncInputWindows;
+ if (!synchronous && !syncInput) {
+ return;
+ }
+
+ if (synchronous) {
+ mTransactionPending = true;
+ }
+ if (syncInput) {
+ mPendingSyncInputWindows = true;
+ }
+
+
+ // applyTransactionState can be called by either the main SF thread or by
+ // another process through setTransactionState. While a given process may wish
+ // to wait on synchronous transactions, the main SF thread should never
+ // be blocked. Therefore, we only wait if isMainThread is false.
+ while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
+ mTransactionPending = false;
+ mPendingSyncInputWindows = false;
+ break;
+ }
+ }
+ } else {
+ // Update VsyncModulator state machine even if transaction is not needed.
+ if (schedule == TransactionSchedule::EarlyStart ||
+ schedule == TransactionSchedule::EarlyEnd) {
+ modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
+ }
}
}
@@ -3621,7 +3626,8 @@
uint32_t SurfaceFlinger::setClientStateLocked(
int64_t frameTimelineVsyncId, const ComposerState& composerState,
int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged,
- std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) {
+ std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks,
+ int originPid, int originUid) {
const layer_state_t& s = composerState.state;
for (auto& listener : s.listeners) {
@@ -3765,10 +3771,14 @@
if (layer->setCornerRadius(s.cornerRadius))
flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) {
+
+ if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur &&
+ originalCallerCanUseBlurs(originPid, originUid)) {
if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
}
- if (what & layer_state_t::eBlurRegionsChanged) {
+
+ if (what & layer_state_t::eBlurRegionsChanged &&
+ originalCallerCanUseBlurs(originPid, originUid)) {
if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eLayerStackChanged) {
@@ -3946,7 +3956,7 @@
}
uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
- bool hasChanges = mInputWindowCommands.merge(inputWindowCommands);
+ bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
return hasChanges ? eTraversalNeeded : 0;
}
@@ -4211,11 +4221,9 @@
d.width = 0;
d.height = 0;
displays.add(d);
-
- // This called on the main thread, apply it directly.
- applyTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0,
- mInputWindowCommands, systemTime(), true, {}, systemTime(), true, false,
- {}, getpid(), getuid(), 0 /* Undefined transactionId */);
+ setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr,
+ mPendingInputWindowCommands, systemTime(), true, {}, false, {},
+ 0 /* Undefined transactionId */);
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
@@ -5392,7 +5400,7 @@
void SurfaceFlinger::repaintEverything() {
mRepaintEverything = true;
- setTransactionFlags(eTransactionNeeded);
+ signalTransaction();
}
void SurfaceFlinger::repaintEverythingForHWC() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bae15dc..b2b7cac 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -344,8 +344,8 @@
virtual uint32_t setClientStateLocked(
int64_t frameTimelineVsyncId, const ComposerState& composerState,
int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged,
- std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
- REQUIRES(mStateLock);
+ std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks,
+ int originPid, int originUid) REQUIRES(mStateLock);
virtual void commitTransactionLocked();
// Used internally by computeLayerBounds() to gets the clip rectangle to use for the
@@ -436,16 +436,15 @@
struct TransactionState {
TransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
- const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
- bool isAutoTimestamp, const client_cache_t& uncacheBuffer,
- int64_t postTime, bool privileged, bool hasListenerCallbacks,
+ int64_t desiredPresentTime, bool isAutoTimestamp,
+ const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged,
+ bool hasListenerCallbacks,
std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
int originUid, uint64_t transactionId)
: frameTimelineVsyncId(frameTimelineVsyncId),
states(composerStates),
displays(displayStates),
flags(transactionFlags),
- inputWindowCommands(inputWindowCommands),
desiredPresentTime(desiredPresentTime),
isAutoTimestamp(isAutoTimestamp),
buffer(uncacheBuffer),
@@ -461,7 +460,6 @@
Vector<ComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
- InputWindowCommands inputWindowCommands;
const int64_t desiredPresentTime;
const bool isAutoTimestamp;
client_cache_t buffer;
@@ -727,7 +725,6 @@
/*
* Transactions
*/
- void flushTransactionQueue();
void applyTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
@@ -735,12 +732,10 @@
const client_cache_t& uncacheBuffer, const int64_t postTime,
bool privileged, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPid, int originUid, uint64_t transactionId)
- REQUIRES(mStateLock);
+ int originPid, int originUid, uint64_t transactionId,
+ bool isMainThread = false) REQUIRES(mStateLock);
// Returns true if at least one transaction was flushed
bool flushTransactionQueues();
- // flush pending transaction that was presented after desiredPresentTime.
- void flushPendingTransactionQueues();
// Returns true if there is at least one transaction that needs to be flushed
bool transactionFlushNeeded();
uint32_t getTransactionFlags(uint32_t flags);
@@ -758,7 +753,7 @@
void commitOffscreenLayers();
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
const Vector<ComposerState>& states,
- bool updateTransactionCounters = false);
+ bool updateTransactionCounters = false) REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
REQUIRES(mStateLock);
@@ -1175,11 +1170,8 @@
uint32_t mTexturePoolSize = 0;
std::vector<uint32_t> mTexturePool;
- mutable Mutex mQueueLock;
- Condition mTransactionQueueCV;
- std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
- mPendingTransactionQueues GUARDED_BY(mQueueLock);
- std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
+ std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;
+
/*
* Feature prototyping
*/
@@ -1256,6 +1248,7 @@
const float mEmulatedDisplayDensity;
sp<os::IInputFlinger> mInputFlinger;
+ InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 3ef63d5..a361b1e 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -68,9 +68,6 @@
Rect(displayState.layerStackSpaceRect), Rect(resolution));
t.apply();
SurfaceComposerClient::Transaction().apply(true);
- // wait for 3 vsyncs to ensure the buffer is latched.
- usleep(static_cast<int32_t>(1e6 / displayConfig.refreshRate) * 3);
-
BufferItem item;
itemConsumer->acquireBuffer(&item, 0, true);
auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index a42daae..13b26fc 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -49,6 +49,7 @@
"HWComposerTest.cpp",
"OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
+ "LayerInfoTest.cpp",
"LayerMetadataTest.cpp",
"MessageQueueTest.cpp",
"SurfaceFlinger_CreateDisplayTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 5abe38b..7024c1e 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -43,8 +43,8 @@
class LayerHistoryTest : public testing::Test {
protected:
static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE;
- static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::MAX_FREQUENT_LAYER_PERIOD_NS;
- static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfo::FREQUENT_LAYER_WINDOW_SIZE;
+ static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::kMaxPeriodForFrequentLayerNs;
+ static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfo::kFrequentLayerWindowSize;
static constexpr auto PRESENT_TIME_HISTORY_DURATION = LayerInfo::HISTORY_DURATION;
static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
LayerInfo::RefreshRateHistory::HISTORY_DURATION;
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
new file mode 100644
index 0000000..d5c9b57
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -0,0 +1,181 @@
+/*
+ * 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 "LayerInfoTest"
+
+#include <gtest/gtest.h>
+
+#include "Fps.h"
+#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfo.h"
+
+namespace android::scheduler {
+
+class LayerInfoTest : public testing::Test {
+protected:
+ using FrameTimeData = LayerInfo::FrameTimeData;
+
+ void setFrameTimes(const std::deque<FrameTimeData>& frameTimes) {
+ layerInfo.mFrameTimes = frameTimes;
+ }
+
+ void setLastRefreshRate(Fps fps) {
+ layerInfo.mLastRefreshRate.reported = fps;
+ layerInfo.mLastRefreshRate.calculated = fps;
+ }
+
+ auto calculateAverageFrameTime() { return layerInfo.calculateAverageFrameTime(); }
+
+ LayerInfo layerInfo{"TestLayerInfo", LayerHistory::LayerVoteType::Heuristic};
+};
+
+namespace {
+
+TEST_F(LayerInfoTest, prefersPresentTime) {
+ std::deque<FrameTimeData> frameTimes;
+ constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
+ constexpr int kNumFrames = 10;
+ for (int i = 1; i <= kNumFrames; i++) {
+ frameTimes.push_back(FrameTimeData{.presentTime = kPeriod * i,
+ .queueTime = 0,
+ .pendingConfigChange = false});
+ }
+ setFrameTimes(frameTimes);
+ const auto averageFrameTime = calculateAverageFrameTime();
+ ASSERT_TRUE(averageFrameTime.has_value());
+ const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+ ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+ << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) {
+ std::deque<FrameTimeData> frameTimes;
+ constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
+ constexpr int kNumFrames = 10;
+ for (int i = 1; i <= kNumFrames; i++) {
+ frameTimes.push_back(FrameTimeData{.presentTime = 0,
+ .queueTime = kPeriod * i,
+ .pendingConfigChange = false});
+ }
+ setFrameTimes(frameTimes);
+ setLastRefreshRate(Fps(20.0f)); // Set to some valid value
+ const auto averageFrameTime = calculateAverageFrameTime();
+ ASSERT_TRUE(averageFrameTime.has_value());
+ const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+ ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+ << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) {
+ std::deque<FrameTimeData> frameTimesWithoutConfigChange;
+ const auto period = Fps(50.0f).getPeriodNsecs();
+ constexpr int kNumFrames = 10;
+ for (int i = 1; i <= kNumFrames; i++) {
+ frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i,
+ .queueTime = period * i,
+ .pendingConfigChange = false});
+ }
+
+ setFrameTimes(frameTimesWithoutConfigChange);
+ ASSERT_TRUE(calculateAverageFrameTime().has_value());
+
+ {
+ // Config change in the first record
+ auto frameTimes = frameTimesWithoutConfigChange;
+ frameTimes[0].pendingConfigChange = true;
+ setFrameTimes(frameTimes);
+ ASSERT_FALSE(calculateAverageFrameTime().has_value());
+ }
+
+ {
+ // Config change in the last record
+ auto frameTimes = frameTimesWithoutConfigChange;
+ frameTimes[frameTimes.size() - 1].pendingConfigChange = true;
+ setFrameTimes(frameTimes);
+ ASSERT_FALSE(calculateAverageFrameTime().has_value());
+ }
+
+ {
+ // Config change in the middle
+ auto frameTimes = frameTimesWithoutConfigChange;
+ frameTimes[frameTimes.size() / 2].pendingConfigChange = true;
+ setFrameTimes(frameTimes);
+ ASSERT_FALSE(calculateAverageFrameTime().has_value());
+ }
+}
+
+// A frame can be recorded twice with very close presentation or queue times.
+// Make sure that this doesn't influence the calculated average FPS.
+TEST_F(LayerInfoTest, ignoresSmallPeriods) {
+ std::deque<FrameTimeData> frameTimes;
+ constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
+ constexpr auto kSmallPeriod = Fps(150.0f).getPeriodNsecs();
+ constexpr int kNumIterations = 10;
+ for (int i = 1; i <= kNumIterations; i++) {
+ frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i,
+ .queueTime = 0,
+ .pendingConfigChange = false});
+
+ // A duplicate frame
+ frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i + kSmallPeriod,
+ .queueTime = 0,
+ .pendingConfigChange = false});
+ }
+ setFrameTimes(frameTimes);
+ const auto averageFrameTime = calculateAverageFrameTime();
+ ASSERT_TRUE(averageFrameTime.has_value());
+ const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+ ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+ << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+// There may be a big period of time between two frames. Make sure that
+// this doesn't influence the calculated average FPS.
+TEST_F(LayerInfoTest, ignoresLargePeriods) {
+ std::deque<FrameTimeData> frameTimes;
+ constexpr auto kExpectedFps = Fps(50.0f);
+ constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
+ constexpr auto kLargePeriod = Fps(9.0f).getPeriodNsecs();
+
+ auto record = [&](nsecs_t time) {
+ frameTimes.push_back(
+ FrameTimeData{.presentTime = time, .queueTime = 0, .pendingConfigChange = false});
+ };
+
+ auto time = kExpectedPeriod; // Start with non-zero time.
+ record(time);
+ time += kLargePeriod;
+ record(time);
+ constexpr int kNumIterations = 10;
+ for (int i = 1; i <= kNumIterations; i++) {
+ time += kExpectedPeriod;
+ record(time);
+ }
+
+ setFrameTimes(frameTimes);
+ const auto averageFrameTime = calculateAverageFrameTime();
+ ASSERT_TRUE(averageFrameTime.has_value());
+ const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+ ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+ << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index e7ded8b..2b8a67d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -360,7 +360,7 @@
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
- auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
+ auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
auto setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
@@ -376,7 +376,7 @@
listenerCallbacks, transactionId);
}
- auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); };
+ auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
return mFlinger->onTransact(code, data, reply, flags);
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index a4a4408..06275c6 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -127,7 +127,7 @@
}
void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime()));
@@ -154,12 +154,12 @@
} else {
EXPECT_LE(returnedTime, applicationTime + s2ns(5));
}
- auto transactionQueue = mFlinger.getPendingTransactionQueue();
+ auto transactionQueue = mFlinger.getTransactionQueue();
EXPECT_EQ(0, transactionQueue.size());
}
void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -183,12 +183,12 @@
nsecs_t returnedTime = systemTime();
EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
// This transaction should have been placed on the transaction queue
- auto transactionQueue = mFlinger.getPendingTransactionQueue();
+ auto transactionQueue = mFlinger.getTransactionQueue();
EXPECT_EQ(1, transactionQueue.size());
}
void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
nsecs_t time = systemTime();
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -239,7 +239,7 @@
}
// check that there is one binder on the pending queue.
- auto transactionQueue = mFlinger.getPendingTransactionQueue();
+ auto transactionQueue = mFlinger.getTransactionQueue();
EXPECT_EQ(1, transactionQueue.size());
auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -258,7 +258,7 @@
};
TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
- ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -275,7 +275,7 @@
transactionA.isAutoTimestamp, transactionA.uncacheBuffer,
mHasListenerCallbacks, mCallbacks, transactionA.id);
- auto& transactionQueue = mFlinger.getPendingTransactionQueue();
+ auto& transactionQueue = mFlinger.getTransactionQueue();
ASSERT_EQ(1, transactionQueue.size());
auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -294,9 +294,9 @@
empty.desiredPresentTime, empty.isAutoTimestamp,
empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id);
- // flush pending transaction queue should flush as desiredPresentTime has
+ // flush transaction queue should flush as desiredPresentTime has
// passed
- mFlinger.flushPendingTransactionQueues();
+ mFlinger.flushTransactionQueues();
EXPECT_EQ(0, transactionQueue.size());
}