Merge "Fix dispatcher logic of handling same key pressed and released from different devices."
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
index 8c0495c..e5c6333 100644
--- a/libs/binder/fuzzer/binder.cpp
+++ b/libs/binder/fuzzer/binder.cpp
@@ -19,6 +19,8 @@
#include "util.h"
#include <android/os/IServiceManager.h>
+#include <binder/ParcelableHolder.h>
+#include <binder/PersistableBundle.h>
using ::android::status_t;
@@ -271,5 +273,20 @@
PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
+
+ // additional parcelable objects defined in libbinder
+ [] (const ::android::Parcel& p, uint8_t data) {
+ using ::android::os::ParcelableHolder;
+ using ::android::Parcelable;
+ FUZZ_LOG() << "about to read ParcelableHolder using readParcelable with status";
+ Parcelable::Stability stability = Parcelable::Stability::STABILITY_LOCAL;
+ if ( (data & 1) == 1 ) {
+ stability = Parcelable::Stability::STABILITY_VINTF;
+ }
+ ParcelableHolder t = ParcelableHolder(stability);
+ status_t status = p.readParcelable(&t);
+ FUZZ_LOG() << "ParcelableHolder status: " << status;
+ },
+ PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
};
// clang-format on
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 5438082..cb752b0 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -35,6 +35,7 @@
#include <SkCanvas.h>
#include <SkImage.h>
+#include <SkShadowUtils.h>
#include <SkSurface.h>
extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
@@ -400,13 +401,12 @@
const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
static_cast<SkScalar>(display.clip.height());
canvas->scale(scaleX, scaleY);
- canvas->clipRect(SkRect::MakeLTRB(display.clip.left, display.clip.top, display.clip.right,
- display.clip.bottom));
+ canvas->clipRect(getSkRect(display.clip));
canvas->drawColor(0, SkBlendMode::kSrc);
for (const auto& layer : layers) {
SkPaint paint;
const auto& bounds = layer->geometry.boundaries;
- const auto dest = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
+ const auto dest = getSkRect(bounds);
if (layer->source.buffer.buffer) {
ATRACE_NAME("DrawImage");
@@ -442,6 +442,13 @@
canvas->save();
canvas->concat(getSkM44(layer->geometry.positionTransform));
+ if (layer->shadow.length > 0) {
+ const auto rect = layer->geometry.roundedCornersRadius > 0
+ ? getSkRect(layer->geometry.roundedCornersCrop)
+ : dest;
+ drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
+ }
+
if (layer->geometry.roundedCornersRadius > 0) {
canvas->drawRRect(getRoundedRect(layer), paint);
} else {
@@ -480,13 +487,24 @@
return NO_ERROR;
}
+inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) {
+ return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) {
+ return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) {
- const auto& crop = layer->geometry.roundedCornersCrop;
- const auto rect = SkRect::MakeLTRB(crop.left, crop.top, crop.right, crop.bottom);
+ const auto rect = getSkRect(layer->geometry.roundedCornersCrop);
const auto cornerRadius = layer->geometry.roundedCornersRadius;
return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);
}
+inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
+ return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
+}
+
inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) {
return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
@@ -494,6 +512,10 @@
matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
}
+inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) {
+ return SkPoint3::Make(vector.x, vector.y, vector.z);
+}
+
size_t SkiaGLRenderEngine::getMaxTextureSize() const {
return mGrContext->maxTextureSize();
}
@@ -502,6 +524,22 @@
return mGrContext->maxRenderTargetSize();
}
+void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect, float cornerRadius,
+ const ShadowSettings& settings) {
+ ATRACE_CALL();
+ const float casterZ = settings.length / 2.0f;
+ const auto shadowShape = cornerRadius > 0
+ ? SkPath::RRect(SkRRect::MakeRectXY(casterRect, cornerRadius, cornerRadius))
+ : SkPath::Rect(casterRect);
+ const auto flags =
+ settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
+
+ SkShadowUtils::DrawShadow(canvas, shadowShape, SkPoint3::Make(0, 0, casterZ),
+ getSkPoint3(settings.lightPos), settings.lightRadius,
+ getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
+ flags);
+}
+
EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext, bool useContextPriority,
Protection protection) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 7103bbd..3da7f25 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -60,11 +60,17 @@
Protection protection);
static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
int hwcFormat, Protection protection);
+ inline SkRect getSkRect(const FloatRect& layer);
+ inline SkRect getSkRect(const Rect& layer);
inline SkRRect getRoundedRect(const LayerSettings* layer);
+ inline SkColor getSkColor(const vec4& color);
inline SkM44 getSkM44(const mat4& matrix);
+ inline SkPoint3 getSkPoint3(const vec3& vector);
base::unique_fd flush();
bool waitFence(base::unique_fd fenceFd);
+ void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
+ const ShadowSettings& shadowSettings);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 7c08e11..ed0d75b 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -38,7 +38,6 @@
"android.hardware.power-cpp",
"libbase",
"libbinder",
- "libbufferhubqueue",
"libcutils",
"libEGL",
"libfmq",
@@ -49,7 +48,6 @@
"liblayers_proto",
"liblog",
"libnativewindow",
- "libpdx_default_transport",
"libprocessgroup",
"libprotobuf-cpp-lite",
"libstatslog",
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6a0f24a..d2262f5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1896,19 +1896,18 @@
bool SurfaceFlinger::handleMessageTransaction() {
ATRACE_CALL();
+
+ if (getTransactionFlags(eTransactionFlushNeeded)) {
+ flushPendingTransactionQueues();
+ flushTransactionQueue();
+ }
+
uint32_t transactionFlags = peekTransactionFlags();
-
- bool flushedATransaction = flushTransactionQueues();
-
bool runHandleTransaction =
- (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) ||
- flushedATransaction ||
- mForceTraversal;
+ (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) || mForceTraversal;
if (runHandleTransaction) {
handleTransaction(eTransactionMask);
- } else {
- getTransactionFlags(eTransactionFlushNeeded);
}
if (transactionFlushNeeded()) {
@@ -2777,7 +2776,6 @@
});
}
- commitInputWindowCommands();
commitTransaction();
}
@@ -2818,11 +2816,6 @@
: nullptr);
}
-void SurfaceFlinger::commitInputWindowCommands() {
- mInputWindowCommands.merge(mPendingInputWindowCommands);
- mPendingInputWindowCommands.clear();
-}
-
void SurfaceFlinger::updateCursorAsync() {
compositionengine::CompositionRefreshArgs refreshArgs;
for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
@@ -3175,50 +3168,52 @@
mForceTraversal = true;
}
-bool SurfaceFlinger::flushTransactionQueues() {
+void SurfaceFlinger::flushPendingTransactionQueues() {
// 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(mStateLock);
+ Mutex::Autolock _l(mQueueLock);
- auto it = mTransactionQueues.begin();
- while (it != mTransactionQueues.end()) {
+ auto it = mPendingTransactionQueues.begin();
+ while (it != mPendingTransactionQueues.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.states, transaction.displays, transaction.flags,
- mPendingInputWindowCommands, transaction.desiredPresentTime,
- transaction.buffer, transaction.postTime,
- transaction.privileged, transaction.hasListenerCallbacks,
- transaction.listenerCallbacks, transaction.originPID,
- transaction.originUID, /*isMainThread*/ true);
transactionQueue.pop();
- flushedATransaction = true;
}
if (transactionQueue.empty()) {
- it = mTransactionQueues.erase(it);
+ it = mPendingTransactionQueues.erase(it);
mTransactionCV.broadcast();
} else {
it = std::next(it, 1);
}
}
}
- return flushedATransaction;
+
+ {
+ Mutex::Autolock _l(mStateLock);
+ for (const auto& transaction : transactions) {
+ applyTransactionState(transaction.states, transaction.displays, transaction.flags,
+ mInputWindowCommands, transaction.desiredPresentTime,
+ transaction.buffer, transaction.postTime, transaction.privileged,
+ transaction.hasListenerCallbacks, transaction.listenerCallbacks,
+ transaction.originPID, transaction.originUID);
+ }
+ }
}
bool SurfaceFlinger::transactionFlushNeeded() {
- return !mTransactionQueues.empty();
+ Mutex::Autolock _l(mQueueLock);
+ return !mPendingTransactionQueues.empty();
}
@@ -3253,51 +3248,125 @@
ATRACE_CALL();
const int64_t postTime = systemTime();
-
bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
+ {
+ Mutex::Autolock _l(mQueueLock);
- Mutex::Autolock _l(mStateLock);
+ // 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()) {
+ 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 = mPendingTransactionQueues.find(applyToken);
+ }
+ }
- // 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()) {
+ // 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);
+ }
+
+ const bool pendingTransactions = itr != mPendingTransactionQueues.end();
+ // Expected present time is computed and cached on invalidate, so it may be stale.
+ if (!pendingTransactions) {
+ mExpectedPresentTime = calculateExpectedPresentTime(systemTime());
+ }
+
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int originPID = ipc->getCallingPid();
+ const int originUID = ipc->getCallingUid();
+
+ if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+ mPendingTransactionQueues[applyToken].emplace(states, displays, flags,
+ inputWindowCommands, desiredPresentTime,
+ uncacheBuffer, postTime, privileged,
+ hasListenerCallbacks, listenerCallbacks,
+ originPID, originUID);
+ setTransactionFlags(eTransactionFlushNeeded);
+ return NO_ERROR;
+ }
+
+ mTransactionQueue.emplace_back(states, displays, flags, inputWindowCommands,
+ desiredPresentTime, uncacheBuffer, postTime, privileged,
+ hasListenerCallbacks, listenerCallbacks, originPID,
+ originUID);
+ }
+
+ {
+ Mutex::Autolock _l(mStateLock);
+
+ 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 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) {
+ setTransactionFlags(eTransactionFlushNeeded, schedule);
+ return NO_ERROR;
+ }
+
+ if (synchronous) {
+ mTransactionPending = true;
+ }
+ if (syncInput) {
+ mPendingSyncInputWindows = true;
+ }
+ setTransactionFlags(eTransactionFlushNeeded, schedule);
+
+ // 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) {
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");
+ // 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;
}
- itr = mTransactionQueues.find(applyToken);
+ }
+ }
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::flushTransactionQueue() {
+ std::vector<TransactionState> transactionQueue;
+ {
+ Mutex::Autolock _l(mQueueLock);
+ if (!mTransactionQueue.empty()) {
+ transactionQueue.swap(mTransactionQueue);
}
}
- const bool pendingTransactions = itr != mTransactionQueues.end();
- // Expected present time is computed and cached on invalidate, so it may be stale.
- if (!pendingTransactions) {
- mExpectedPresentTime = calculateExpectedPresentTime(systemTime());
+ Mutex::Autolock _l(mStateLock);
+ for (const auto& t : transactionQueue) {
+ applyTransactionState(t.states, t.displays, t.flags, t.inputWindowCommands,
+ t.desiredPresentTime, t.buffer, t.postTime, t.privileged,
+ t.hasListenerCallbacks, t.listenerCallbacks, t.originPID,
+ t.originUID);
}
-
- IPCThreadState* ipc = IPCThreadState::self();
- const int originPID = ipc->getCallingPid();
- const int originUID = ipc->getCallingUid();
-
- if (pendingTransactions || !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
- mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
- uncacheBuffer, postTime, privileged,
- hasListenerCallbacks, listenerCallbacks, originPID,
- originUID);
- setTransactionFlags(eTransactionFlushNeeded);
- return NO_ERROR;
- }
-
- applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
- uncacheBuffer, postTime, privileged, hasListenerCallbacks,
- listenerCallbacks, originPID, originUID, /*isMainThread*/ false);
- return NO_ERROR;
}
void SurfaceFlinger::applyTransactionState(
@@ -3305,25 +3374,9 @@
const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged,
bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPID, int originUID, bool isMainThread) {
+ int32_t originPID, int32_t originUID) {
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
- // caller after a few seconds.
- ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
- "waiting for previous animation frame");
- mAnimTransactionPending = false;
- break;
- }
- }
- }
-
for (const DisplayState& display : displays) {
transactionFlags |= setDisplayStateLocked(display);
}
@@ -3379,80 +3432,25 @@
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)) {
+ if (transactionFlags && mInterceptor->isEnabled()) {
+ mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags, originPID,
+ originUID);
+ }
+
+ // 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;
}
- 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);
- }
-
- // 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);
- }
-
// this triggers the transaction
- setTransactionFlags(transactionFlags, schedule);
+ setTransactionFlags(transactionFlags);
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);
- }
}
}
@@ -3831,7 +3829,7 @@
}
uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
- bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
+ bool hasChanges = mInputWindowCommands.merge(inputWindowCommands);
return hasChanges ? eTraversalNeeded : 0;
}
@@ -4088,8 +4086,9 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false,
- {});
+ // This called on the main thread, apply it directly.
+ applyTransactionState(state, displays, 0, mInputWindowCommands, -1, {}, systemTime(), true,
+ false, {}, getpid(), getuid());
setPowerModeInternal(display, hal::PowerMode::ON);
const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
@@ -5254,7 +5253,7 @@
void SurfaceFlinger::repaintEverything() {
mRepaintEverything = true;
- signalTransaction();
+ setTransactionFlags(eTransactionNeeded);
}
void SurfaceFlinger::repaintEverythingForHWC() {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3b4d5d4..8b2c4b8 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -433,13 +433,15 @@
struct TransactionState {
TransactionState(const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
- int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
- int64_t postTime, bool privileged, bool hasListenerCallbacks,
+ const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+ const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged,
+ bool hasListenerCallbacks,
std::vector<ListenerCallbacks> listenerCallbacks, int originPID,
int originUID)
: states(composerStates),
displays(displayStates),
flags(transactionFlags),
+ inputWindowCommands(inputWindowCommands),
desiredPresentTime(desiredPresentTime),
buffer(uncacheBuffer),
postTime(postTime),
@@ -452,6 +454,7 @@
Vector<ComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
+ InputWindowCommands inputWindowCommands;
const int64_t desiredPresentTime;
client_cache_t buffer;
const int64_t postTime;
@@ -707,6 +710,7 @@
/*
* Transactions
*/
+ void flushTransactionQueue();
void applyTransactionState(const Vector<ComposerState>& state,
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
@@ -714,10 +718,9 @@
const client_cache_t& uncacheBuffer, const int64_t postTime,
bool privileged, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPID, int originUID, bool isMainThread = false)
- REQUIRES(mStateLock);
- // Returns true if at least one transaction was flushed
- bool flushTransactionQueues();
+ int32_t originPID, int32_t originUID) REQUIRES(mStateLock);
+ // 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);
@@ -1161,8 +1164,10 @@
uint32_t mTexturePoolSize = 0;
std::vector<uint32_t> mTexturePool;
- std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;
-
+ mutable Mutex mQueueLock;
+ std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
+ mPendingTransactionQueues GUARDED_BY(mQueueLock);
+ std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
/*
* Feature prototyping
*/
@@ -1239,7 +1244,6 @@
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 01badf4..2a48c2c 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -68,6 +68,9 @@
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/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 98b20e8..1c9c496 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -346,7 +346,7 @@
return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
}
- auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
+ auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
auto setTransactionState(const Vector<ComposerState>& states,
const Vector<DisplayState>& displays, uint32_t flags,
@@ -360,7 +360,7 @@
hasListenerCallbacks, listenerCallbacks);
}
- auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+ auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); };
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 28415bc..eaf2299 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -122,7 +122,7 @@
}
void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime()));
@@ -146,12 +146,12 @@
} else {
EXPECT_LE(returnedTime, applicationTime + s2ns(5));
}
- auto transactionQueue = mFlinger.getTransactionQueue();
+ auto transactionQueue = mFlinger.getPendingTransactionQueue();
EXPECT_EQ(0, transactionQueue.size());
}
void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -172,12 +172,12 @@
nsecs_t returnedTime = systemTime();
EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
// This transaction should have been placed on the transaction queue
- auto transactionQueue = mFlinger.getTransactionQueue();
+ auto transactionQueue = mFlinger.getPendingTransactionQueue();
EXPECT_EQ(1, transactionQueue.size());
}
void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
nsecs_t time = systemTime();
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -222,7 +222,7 @@
}
// check that there is one binder on the pending queue.
- auto transactionQueue = mFlinger.getTransactionQueue();
+ auto transactionQueue = mFlinger.getPendingTransactionQueue();
EXPECT_EQ(1, transactionQueue.size());
auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -241,7 +241,7 @@
};
TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
- ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+ ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
// called in SurfaceFlinger::signalTransaction
EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -257,7 +257,7 @@
transactionA.desiredPresentTime, transactionA.uncacheBuffer,
mHasListenerCallbacks, mCallbacks);
- auto& transactionQueue = mFlinger.getTransactionQueue();
+ auto& transactionQueue = mFlinger.getPendingTransactionQueue();
ASSERT_EQ(1, transactionQueue.size());
auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -275,9 +275,9 @@
empty.inputWindowCommands, empty.desiredPresentTime,
empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks);
- // flush transaction queue should flush as desiredPresentTime has
+ // flush pending transaction queue should flush as desiredPresentTime has
// passed
- mFlinger.flushTransactionQueues();
+ mFlinger.flushPendingTransactionQueues();
EXPECT_EQ(0, transactionQueue.size());
}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 0f791c9..48090af 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -258,7 +258,11 @@
bool shared;
struct Image {
- Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
+ Image()
+ : image(VK_NULL_HANDLE),
+ dequeue_fence(-1),
+ release_fence(-1),
+ dequeued(false) {}
VkImage image;
android::sp<ANativeWindowBuffer> buffer;
// The fence is only valid when the buffer is dequeued, and should be
@@ -266,6 +270,10 @@
// closed: either by closing it explicitly when queueing the buffer,
// or by passing ownership e.g. to ANativeWindow::cancelBuffer().
int dequeue_fence;
+ // This fence is a dup of the sync fd returned from the driver via
+ // vkQueueSignalReleaseImageANDROID upon vkQueuePresentKHR. We must
+ // ensure it is closed upon re-presenting or releasing the image.
+ int release_fence;
bool dequeued;
} images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
@@ -280,10 +288,19 @@
return reinterpret_cast<Swapchain*>(handle);
}
+static bool IsFencePending(int fd) {
+ if (fd < 0)
+ return false;
+
+ errno = 0;
+ return sync_wait(fd, 0 /* timeout */) == -1 && errno == ETIME;
+}
+
void ReleaseSwapchainImage(VkDevice device,
ANativeWindow* window,
int release_fence,
- Swapchain::Image& image) {
+ Swapchain::Image& image,
+ bool defer_if_pending) {
ATRACE_CALL();
ALOG_ASSERT(release_fence == -1 || image.dequeued,
@@ -319,10 +336,18 @@
close(release_fence);
}
}
-
+ release_fence = -1;
image.dequeued = false;
}
+ if (defer_if_pending && IsFencePending(image.release_fence))
+ return;
+
+ if (image.release_fence >= 0) {
+ close(image.release_fence);
+ image.release_fence = -1;
+ }
+
if (image.image) {
ATRACE_BEGIN("DestroyImage");
GetData(device).driver.DestroyImage(device, image.image, nullptr);
@@ -338,7 +363,8 @@
return;
for (uint32_t i = 0; i < swapchain->num_images; i++) {
if (!swapchain->images[i].dequeued)
- ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
+ ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i],
+ true);
}
swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
swapchain->timing.clear();
@@ -996,7 +1022,7 @@
}
for (uint32_t i = 0; i < swapchain->num_images; i++) {
- ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
+ ReleaseSwapchainImage(device, window, -1, swapchain->images[i], false);
}
if (active) {
@@ -1628,6 +1654,9 @@
ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
swapchain_result = result;
}
+ if (img.release_fence >= 0)
+ close(img.release_fence);
+ img.release_fence = fence < 0 ? -1 : dup(fence);
if (swapchain.surface.swapchain_handle ==
present_info->pSwapchains[sc]) {
@@ -1761,7 +1790,7 @@
WorstPresentResult(swapchain_result, VK_SUBOPTIMAL_KHR);
}
} else {
- ReleaseSwapchainImage(device, nullptr, fence, img);
+ ReleaseSwapchainImage(device, nullptr, fence, img, true);
swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
}