From 03fbf9c267ec8883ff5561034b30536baa9d4d86 Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Wed, 3 Jun 2020 10:01:34 -0700 Subject: Use GraphicBuffer::toAHardwareBuffer() instead of casting Test: build Change-Id: I29a9b02a86d6163f7a181ed150a99987eaa61d45 --- libs/gui/Surface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2bf8ff7581..1efd98bb33 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1493,7 +1493,7 @@ int Surface::dispatchGetLastQueuedBuffer(va_list args) { int result = mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, matrix); if (graphicBuffer != nullptr) { - *buffer = reinterpret_cast(graphicBuffer.get()); + *buffer = graphicBuffer->toAHardwareBuffer(); AHardwareBuffer_acquire(*buffer); } else { *buffer = nullptr; -- cgit v1.2.3-59-g8ed1b From 74e17562e4166e11c2e4f33126088c5ed35ea0e7 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Mon, 24 Aug 2020 18:18:19 -0700 Subject: SurfaceFlinger: Shared timeline plumbing Add plumbing to get shared timeline data from Surface Flinger to HWUI and back. Bug: 162890382 Bug: 162888881 Test: SF unit tests Change-Id: Ifb76e6bf28d43c051e6c8ff568437ec9a106b865 --- libs/gui/DisplayEventDispatcher.cpp | 17 ++++--- libs/gui/ISurfaceComposer.cpp | 59 ++++++++++++++++++++++ libs/gui/Surface.cpp | 11 ++++ libs/gui/include/gui/DisplayEventDispatcher.h | 5 +- libs/gui/include/gui/DisplayEventReceiver.h | 1 + libs/gui/include/gui/ISurfaceComposer.h | 8 +++ libs/gui/include/gui/Surface.h | 1 + libs/gui/tests/DisplayEventStructLayout_test.cpp | 2 + libs/gui/tests/Surface_test.cpp | 9 +++- libs/nativedisplay/AChoreographer.cpp | 27 +++++++--- .../private/android/choreographer.h | 6 +++ libs/nativedisplay/libnativedisplay.map.txt | 1 + libs/nativewindow/include/system/window.h | 7 +++ services/surfaceflinger/Layer.cpp | 4 ++ services/surfaceflinger/Layer.h | 4 ++ services/surfaceflinger/Scheduler/EventThread.cpp | 9 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 16 +++++- services/surfaceflinger/SurfaceFlinger.h | 3 ++ 18 files changed, 170 insertions(+), 20 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index 2cc7c34c40..7e894b4b79 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -73,7 +73,8 @@ status_t DisplayEventDispatcher::scheduleVsync() { nsecs_t vsyncTimestamp; PhysicalDisplayId vsyncDisplayId; uint32_t vsyncCount; - if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { + int64_t vsyncId; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) { ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this, ns2ms(static_cast(vsyncTimestamp))); } @@ -116,11 +117,13 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { nsecs_t vsyncTimestamp; PhysicalDisplayId vsyncDisplayId; uint32_t vsyncCount; - if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { - ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%s, count=%d", this, - ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount); + int64_t vsyncId; + if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) { + ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 + ", displayId=%s, count=%d, vsyncId=%" PRId64, + this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, vsyncId); mWaitingForVsync = false; - dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); + dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncId); } return 1; // keep the callback @@ -128,10 +131,11 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, - uint32_t* outCount) { + uint32_t* outCount, int64_t* outVsyncId) { bool gotVsync = false; DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE]; ssize_t n; + *outVsyncId = 0; while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) { ALOGV("dispatcher %p ~ Read %d events.", this, int(n)); for (ssize_t i = 0; i < n; i++) { @@ -144,6 +148,7 @@ bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp, *outTimestamp = ev.header.timestamp; *outDisplayId = ev.header.displayId; *outCount = ev.vsync.count; + *outVsyncId = ev.vsync.vsyncId; break; case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected); diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0ac493dab1..8b65ea1cbe 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1150,6 +1150,38 @@ public: return NO_ERROR; } + + virtual status_t setFrameTimelineVsync(const sp& surface, + int64_t frameTimelineVsyncId) { + Parcel data, reply; + status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (err != NO_ERROR) { + ALOGE("setFrameTimelineVsync: failed writing interface token: %s (%d)", strerror(-err), + -err); + return err; + } + + err = data.writeStrongBinder(IInterface::asBinder(surface)); + if (err != NO_ERROR) { + ALOGE("setFrameTimelineVsync: failed writing strong binder: %s (%d)", strerror(-err), + -err); + return err; + } + + err = data.writeInt64(frameTimelineVsyncId); + if (err != NO_ERROR) { + ALOGE("setFrameTimelineVsync: failed writing int64_t: %s (%d)", strerror(-err), -err); + return err; + } + + err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_VSYNC, data, &reply); + if (err != NO_ERROR) { + ALOGE("setFrameTimelineVsync: failed to transact: %s (%d)", strerror(-err), err); + return err; + } + + return reply.readInt32(); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1950,6 +1982,33 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } + case SET_FRAME_TIMELINE_VSYNC: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp binder; + status_t err = data.readStrongBinder(&binder); + if (err != NO_ERROR) { + ALOGE("setFrameTimelineVsync: failed to read strong binder: %s (%d)", + strerror(-err), -err); + return err; + } + sp surface = interface_cast(binder); + if (!surface) { + ALOGE("setFrameTimelineVsync: failed to cast to IGraphicBufferProducer: %s (%d)", + strerror(-err), -err); + return err; + } + int64_t frameTimelineVsyncId; + err = data.readInt64(&frameTimelineVsyncId); + if (err != NO_ERROR) { + ALOGE("setFrameTimelineVsync: failed to read int64_t: %s (%d)", strerror(-err), + -err); + return err; + } + + status_t result = setFrameTimelineVsync(surface, frameTimelineVsyncId); + reply->writeInt32(result); + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e45b3d1be4..9ce8442579 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1207,6 +1207,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: res = dispatchGetLastQueuedBuffer(args); break; + case NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC: + res = dispatchSetFrameTimelineVsync(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1513,6 +1516,14 @@ int Surface::dispatchGetLastQueuedBuffer(va_list args) { return result; } +int Surface::dispatchSetFrameTimelineVsync(va_list args) { + ATRACE_CALL(); + auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); + + ALOGV("Surface::dispatchSetFrameTimelineVsync"); + return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, frameTimelineVsyncId); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index eb5b00418a..cf598ead14 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -43,7 +43,8 @@ private: DisplayEventReceiver mReceiver; bool mWaitingForVsync; - virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0; + virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, + int64_t vsyncId) = 0; virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) = 0; virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, @@ -53,6 +54,6 @@ private: virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0; bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, - uint32_t* outCount); + uint32_t* outCount, int64_t* outVsyncId); }; } // namespace android diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index 0d0d10289c..df3118ff6d 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -73,6 +73,7 @@ public: uint32_t count; nsecs_t expectedVSyncTimestamp __attribute__((aligned(8))); nsecs_t deadlineTimestamp __attribute__((aligned(8))); + int64_t vsyncId; }; struct Hotplug { diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e057b68b60..7c25b974fe 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -479,6 +479,13 @@ public: * for tests. Release the token by releasing the returned IBinder reference. */ virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) = 0; + + /* + * Sets the frame timeline vsync id received from choreographer that corresponds to next + * buffer submitted on that surface. + */ + virtual status_t setFrameTimelineVsync(const sp& surface, + int64_t frameTimelineVsyncId) = 0; }; // ---------------------------------------------------------------------------- @@ -538,6 +545,7 @@ public: SET_GAME_CONTENT_TYPE, SET_FRAME_RATE, ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, + SET_FRAME_TIMELINE_VSYNC, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 55b4101908..a68f2e7ce8 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -265,6 +265,7 @@ private: int dispatchAddQueueInterceptor(va_list args); int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); + int dispatchSetFrameTimelineVsync(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp index 4bcb7953c6..72109109c4 100644 --- a/libs/gui/tests/DisplayEventStructLayout_test.cpp +++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp @@ -33,6 +33,8 @@ TEST(DisplayEventStructLayoutTest, TestEventAlignment) { CHECK_OFFSET(DisplayEventReceiver::Event::VSync, count, 0); CHECK_OFFSET(DisplayEventReceiver::Event::VSync, expectedVSyncTimestamp, 8); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, deadlineTimestamp, 16); + CHECK_OFFSET(DisplayEventReceiver::Event::VSync, vsyncId, 24); CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index aedba2aebd..8d699978c7 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -868,7 +868,14 @@ public: return NO_ERROR; } - status_t acquireFrameRateFlexibilityToken(sp* /*outToken*/) { return NO_ERROR; } + status_t acquireFrameRateFlexibilityToken(sp* /*outToken*/) override { + return NO_ERROR; + } + + status_t setFrameTimelineVsync(const sp& /*surface*/, + int64_t /*frameTimelineVsyncId*/) override { + return NO_ERROR; + } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index ff1b5e6d34..b7c5b2a3d4 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -128,11 +128,14 @@ public: static Choreographer* getForThread(); virtual ~Choreographer() override EXCLUDES(gChoreographers.lock); + int64_t getVsyncId() const; + private: Choreographer(const Choreographer&) = delete; - void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override; + void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, + int64_t vsyncId) override; void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override; void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId, nsecs_t vsyncPeriod) override; @@ -146,6 +149,7 @@ private: std::vector mRefreshRateCallbacks; nsecs_t mLatestVsyncPeriod = -1; + int64_t mLastVsyncId = -1; const sp mLooper; const std::thread::id mThreadId; @@ -350,7 +354,7 @@ void Choreographer::handleRefreshRateUpdates() { // TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the // internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for // the internal display implicitly. -void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) { +void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, int64_t vsyncId) { std::vector callbacks{}; { std::lock_guard _l{mLock}; @@ -360,6 +364,7 @@ void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t mFrameCallbacks.pop(); } } + mLastVsyncId = vsyncId; for (const auto& cb : callbacks) { if (cb.callback64 != nullptr) { cb.callback64(timestamp, cb.data); @@ -404,6 +409,10 @@ void Choreographer::handleMessage(const Message& message) { } } +int64_t Choreographer::getVsyncId() const { + return mLastVsyncId; +} + } // namespace android using namespace android; @@ -411,6 +420,11 @@ static inline Choreographer* AChoreographer_to_Choreographer(AChoreographer* cho return reinterpret_cast(choreographer); } +static inline const Choreographer* AChoreographer_to_Choreographer( + const AChoreographer* choreographer) { + return reinterpret_cast(choreographer); +} + // Glue for private C api namespace android { void AChoreographer_signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock) { @@ -468,15 +482,14 @@ void AChoreographer_routeUnregisterRefreshRateCallback(AChoreographer* choreogra return AChoreographer_unregisterRefreshRateCallback(choreographer, callback, data); } +int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer) { + return AChoreographer_to_Choreographer(choreographer)->getVsyncId(); +} + } // namespace android /* Glue for the NDK interface */ -static inline const Choreographer* AChoreographer_to_Choreographer( - const AChoreographer* choreographer) { - return reinterpret_cast(choreographer); -} - static inline AChoreographer* Choreographer_to_AChoreographer(Choreographer* choreographer) { return reinterpret_cast(choreographer); } diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h index 21649304bf..1d57c155ec 100644 --- a/libs/nativedisplay/include-private/private/android/choreographer.h +++ b/libs/nativedisplay/include-private/private/android/choreographer.h @@ -29,6 +29,12 @@ void AChoreographer_initJVM(JNIEnv* env); // for consumption by callbacks. void AChoreographer_signalRefreshRateCallbacks(int64_t vsyncPeriod); +// Returns the vsync id of the last frame callback. Client are expected to call +// this function from their frame callback function to get the vsyncId and pass +// it together with a buffer or transaction to the Surface Composer. Calling +// this function from anywhere else will return an undefined value. +int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer); + // Trampoline functions allowing libandroid.so to define the NDK symbols without including // the entirety of libnativedisplay as a whole static lib. As libnativedisplay // maintains global state, libnativedisplay can never be directly statically diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt index fc59431d08..5ed2e496d3 100644 --- a/libs/nativedisplay/libnativedisplay.map.txt +++ b/libs/nativedisplay/libnativedisplay.map.txt @@ -29,6 +29,7 @@ LIBNATIVEDISPLAY_PLATFORM { android::AChoreographer_routeRegisterRefreshRateCallback*; android::AChoreographer_routeUnregisterRefreshRateCallback*; android::AChoreographer_signalRefreshRateCallbacks*; + android::AChoreographer_getVsyncId*; android::ADisplay_acquirePhysicalDisplays*; android::ADisplay_release*; android::ADisplay_getMaxSupportedFps*; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index b78fc5dbbc..138e08f490 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -255,6 +255,7 @@ enum { NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */ NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ + NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC = 48, /* private */ // clang-format on }; @@ -1022,6 +1023,12 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo (int)compatibility); } +static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window, + int64_t frameTimelineVsyncId) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC, + frameTimelineVsyncId); +} + // ------------------------------------------------------------------------------------------------ // Candidates for APEX visibility // These functions are planned to be made stable for APEX modules, but have not diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index eced6bdbe2..152c044ceb 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1435,6 +1435,10 @@ bool Layer::setFrameRate(FrameRate frameRate) { return true; } +void Layer::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { + mFrameTimelineVsyncId = frameTimelineVsyncId; +} + Layer::FrameRate Layer::getFrameRateForLayerTree() const { const auto frameRate = getDrawingState().frameRate; if (frameRate.rate > 0 || frameRate.type == FrameRateCompatibility::NoVote) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 913f13ad95..f77a828c09 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -822,6 +822,8 @@ public: bool setFrameRate(FrameRate); + void setFrameTimelineVsync(int64_t frameTimelineVsyncId); + // Creates a new handle each time, so we only expect // this to be called once. sp getHandle(); @@ -1022,6 +1024,8 @@ protected: // Can only be accessed with the SF state lock held. bool mChildrenChanged{false}; + std::optional mFrameTimelineVsyncId; + // Window types from WindowManager.LayoutParams const InputWindowInfo::Type mWindowType; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index f513535658..77b2f4273e 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -99,12 +99,13 @@ DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t tim DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp, uint32_t count, nsecs_t expectedVSyncTimestamp, - nsecs_t deadlineTimestamp) { + nsecs_t deadlineTimestamp, int64_t vsyncId) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp}; event.vsync.count = count; event.vsync.expectedVSyncTimestamp = expectedVSyncTimestamp; event.vsync.deadlineTimestamp = deadlineTimestamp; + event.vsync.vsyncId = vsyncId; return event; } @@ -291,8 +292,9 @@ void EventThread::onVSyncEvent(nsecs_t timestamp, nsecs_t expectedVSyncTimestamp std::lock_guard lock(mMutex); LOG_FATAL_IF(!mVSyncState); + // TODO(b/162890590): use TokenManager to populate vsyncId mPendingEvents.push_back(makeVSync(mVSyncState->displayId, timestamp, ++mVSyncState->count, - expectedVSyncTimestamp, deadlineTimestamp)); + expectedVSyncTimestamp, deadlineTimestamp, /*vsyncId=*/0)); mCondition.notify_all(); } @@ -416,9 +418,10 @@ void EventThread::threadMain(std::unique_lock& lock) { const auto now = systemTime(SYSTEM_TIME_MONOTONIC); const auto deadlineTimestamp = now + timeout.count(); const auto expectedVSyncTime = deadlineTimestamp + timeout.count(); + // TODO(b/162890590): use TokenManager to populate vsyncId mPendingEvents.push_back(makeVSync(mVSyncState->displayId, now, ++mVSyncState->count, expectedVSyncTime, - deadlineTimestamp)); + deadlineTimestamp, /*vsyncId=*/0)); } } } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9d35a3fca6..51107d31da 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5001,7 +5001,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // captureLayers and captureDisplay will handle the permission check in the function case CAPTURE_LAYERS: case CAPTURE_DISPLAY: - case SET_DISPLAY_BRIGHTNESS: { + case SET_DISPLAY_BRIGHTNESS: + case SET_FRAME_TIMELINE_VSYNC: { return OK; } @@ -6333,6 +6334,19 @@ void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { })); } +status_t SurfaceFlinger::setFrameTimelineVsync(const sp& surface, + int64_t frameTimelineVsyncId) { + Mutex::Autolock lock(mStateLock); + if (!authenticateSurfaceTextureLocked(surface)) { + ALOGE("Attempt to set frame timeline vsync on an unrecognized IGraphicBufferProducer"); + return BAD_VALUE; + } + + sp layer = (static_cast(surface.get()))->getLayer(); + layer->setFrameTimelineVsync(frameTimelineVsyncId); + return NO_ERROR; +} + void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { static_cast(schedule([=] { std::unique_ptr overlay; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 28762c927c..faee775b02 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -597,6 +597,9 @@ private: int8_t compatibility) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; + status_t setFrameTimelineVsync(const sp& surface, + int64_t frameTimelineVsyncId) override; + // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; -- cgit v1.2.3-59-g8ed1b From 9b611b7f4d1a8b8b5e519007b5d841ace3ed696c Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 19 Oct 2020 12:00:23 -0700 Subject: BLASTBufferQueue: Support setFrameTimelineVsync Surface::setFrameTimelineVsync calls through to SurfaceFlinger using the IGBP as a token. But of course in the case of BBQ we have no IGBP on the server side, and this will produce errors. To fix this we continue overriding Surface methods in the BBQSurface , and forward through to the SurfaceControl variants of the function. Unlike the previous CL for setFrameRate, this is a currently un-released API, and so I'd also like to investigate as a follow-up...can we go SurfaceControl path only? Bug: 170890018 Test: Existing tests pass Change-Id: I5316c38f462c3808d5769ede6666594b911c8242 --- libs/gui/BLASTBufferQueue.cpp | 12 ++++++++++++ libs/gui/LayerState.cpp | 2 ++ libs/gui/Surface.cpp | 7 ++++++- libs/gui/SurfaceComposerClient.cpp | 13 +++++++++++++ libs/gui/include/gui/BLASTBufferQueue.h | 1 + libs/gui/include/gui/LayerState.h | 3 +++ libs/gui/include/gui/Surface.h | 1 + libs/gui/include/gui/SurfaceComposerClient.h | 3 +++ services/surfaceflinger/SurfaceFlinger.cpp | 9 +++++++-- 9 files changed, 48 insertions(+), 3 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 6ae6df196d..c8e1f3d1a0 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -381,6 +381,10 @@ public: } return mBbq->setFrameRate(frameRate, compatibility); } + + status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { + return mBbq->setFrameTimelineVsync(frameTimelineVsyncId); + } }; // TODO: Can we coalesce this with frame updates? Need to confirm @@ -393,6 +397,14 @@ status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) { .apply(); } +status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { + std::unique_lock _lock{mMutex}; + SurfaceComposerClient::Transaction t; + + return t.setFrameTimelineVsync(mSurfaceControl, frameTimelineVsyncId) + .apply(); +} + sp BLASTBufferQueue::getSurface() { return new BBQSurface(mProducer, true, this); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2e4d279a5b..433312639d 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -146,6 +146,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); + SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); return NO_ERROR; } @@ -250,6 +251,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); + SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId); return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 9ce8442579..167bef1449 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1521,7 +1521,7 @@ int Surface::dispatchSetFrameTimelineVsync(va_list args) { auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); ALOGV("Surface::dispatchSetFrameTimelineVsync"); - return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, frameTimelineVsyncId); + return setFrameTimelineVsync(frameTimelineVsyncId); } bool Surface::transformToDisplayInverse() { @@ -2288,4 +2288,9 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); } +status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { + return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, + frameTimelineVsyncId); +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 105969bd42..791750fd37 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1510,6 +1510,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( + const sp& sc, int64_t frameTimelineVsyncId) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eFrameTimelineVsyncChanged; + s->frameTimelineVsyncId = frameTimelineVsyncId; + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index d477bea3ac..1410b12e12 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -86,6 +86,7 @@ public: void flushShadowQueue() { mFlushShadowQueue = true; } status_t setFrameRate(float frameRate, int8_t compatibility); + status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); virtual ~BLASTBufferQueue() = default; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 5942fd03af..ff3a87d98f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -127,6 +127,7 @@ struct layer_state_t { eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, eFrameNumberChanged = 0x400'00000000, + eFrameTimelineVsyncChanged = 0x800'00000000, }; layer_state_t(); @@ -227,6 +228,8 @@ struct layer_state_t { // Used by BlastBufferQueue to forward the framenumber generated by the // graphics producer. uint64_t frameNumber; + + int64_t frameTimelineVsyncId; }; struct ComposerState { diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 6a1eaa2075..c2b5ec4c4d 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -180,6 +180,7 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const; virtual status_t setFrameRate(float frameRate, int8_t compatibility); + virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); protected: virtual ~Surface(); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index ce1a0a5f30..138f82cd21 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -532,6 +532,9 @@ public: // Sets the frame timeline vsync id received from choreographer that corresponds // to the transaction. Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId); + // Variant that only applies to a specific SurfaceControl. + Transaction& setFrameTimelineVsync(const sp& sc, + int64_t frameTimelineVsyncId); status_t setDisplaySurface(const sp& token, const sp& bufferProducer); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 964bd015f2..b6ed68fa49 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3770,6 +3770,13 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } + if (what & layer_state_t::eFrameTimelineVsyncChanged) { + layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime); + } else { + // TODO (b/171252403) We are calling this too much, potentially triggering + // unnecessary work + layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime); + } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { flags |= eTraversalNeeded | eTransformHintUpdateNeeded; @@ -3829,8 +3836,6 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } - layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime); - if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener -- cgit v1.2.3-59-g8ed1b From 992496bd2e1af9c93bce33216034dd5419acb444 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Thu, 22 Oct 2020 17:27:21 -0700 Subject: Allow creating child surfaces from BlastBufferQueue App such as Chrome create child surfaces and parent them to surfaces provided by SurfaceView. When we enable the blast adapter for SurfaceView, the IGBP returned to the app is created in the client and SurfaceFlinger does not know about it. When the app creates a child surface and provides the IGBP as the parent surface identifier, SF fails to validate the IGBP and the surface is not created. This can be avoid if the client creates the child surface from the SV SurfaceControl but we still need to support existing APIs. To fix this, when we create a Surface from the adapter, pass in the handle of the Blast SurfaceControl. When calling ASurfaceControl_createFromWindow, use this handle to identify the parent. Bug: 168917217 Test: adb shell settings put global use_blast_adapter_sv 1 & launch chrome Change-Id: I404bbd29b63044260f5403aae60f039a36eeea8b --- libs/gui/BLASTBufferQueue.cpp | 17 ++++++++++------- libs/gui/Surface.cpp | 4 +++- libs/gui/SurfaceComposerClient.cpp | 12 ++++-------- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- libs/gui/include/gui/Surface.h | 18 +++++++++++++++--- libs/gui/include/gui/SurfaceComposerClient.h | 20 ++++++++++---------- libs/gui/include/gui/view/Surface.h | 2 ++ libs/gui/view/Surface.cpp | 5 ++++- services/surfaceflinger/tests/EffectLayer_test.cpp | 6 +++--- .../surfaceflinger/tests/InvalidHandles_test.cpp | 2 +- services/surfaceflinger/tests/LayerTransactionTest.h | 5 +++-- services/surfaceflinger/tests/LayerUpdate_test.cpp | 5 +++-- .../surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp | 8 ++++---- 13 files changed, 63 insertions(+), 43 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index c8e1f3d1a0..0e47676dd6 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -357,11 +357,9 @@ class BBQSurface : public Surface { private: sp mBbq; public: - BBQSurface(const sp& igbp, bool controlledByApp, - const sp& bbq) : - Surface(igbp, controlledByApp), - mBbq(bbq) { - } + BBQSurface(const sp& igbp, bool controlledByApp, + const sp& scHandle, const sp& bbq) + : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {} void allocateBuffers() override { uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; @@ -405,8 +403,13 @@ status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { .apply(); } -sp BLASTBufferQueue::getSurface() { - return new BBQSurface(mProducer, true, this); +sp BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) { + std::unique_lock _lock{mMutex}; + sp scHandle = nullptr; + if (includeSurfaceControlHandle && mSurfaceControl) { + scHandle = mSurfaceControl->getHandle(); + } + return new BBQSurface(mProducer, true, scHandle, this); } } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 167bef1449..c1155ab73a 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -63,7 +63,8 @@ bool isInterceptorRegistrationOp(int op) { } // namespace -Surface::Surface(const sp& bufferProducer, bool controlledByApp) +Surface::Surface(const sp& bufferProducer, bool controlledByApp, + const sp& surfaceControlHandle) : mGraphicBufferProducer(bufferProducer), mCrop(Rect::EMPTY_RECT), mBufferAge(0), @@ -111,6 +112,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mProducerControlledByApp = controlledByApp; mSwapIntervalZero = false; mMaxBufferCount = NUM_BUFFER_SLOTS; + mSurfaceControlHandle = surfaceControlHandle; } Surface::~Surface() { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 60966e1915..4b7d4b1a5d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1628,11 +1628,11 @@ void SurfaceComposerClient::dispose() { sp SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, - SurfaceControl* parent, + const sp& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { sp s; - createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata), + createSurfaceChecked(name, w, h, format, &s, flags, parentHandle, std::move(metadata), outTransformHint); return s; } @@ -1669,20 +1669,16 @@ sp SurfaceComposerClient::createWithSurfaceParent(const String8& status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h, PixelFormat format, sp* outSurface, uint32_t flags, - SurfaceControl* parent, LayerMetadata metadata, + const sp& parentHandle, + LayerMetadata metadata, uint32_t* outTransformHint) { sp sur; status_t err = mStatus; if (mStatus == NO_ERROR) { sp handle; - sp parentHandle; sp gbp; - if (parent != nullptr) { - parentHandle = parent->getHandle(); - } - uint32_t transformHint = 0; int32_t id = -1; err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata), diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 1410b12e12..0d457bfe4a 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -72,7 +72,7 @@ public: sp getIGraphicBufferProducer() const { return mProducer; } - sp getSurface(); + sp getSurface(bool includeSurfaceControlHandle); void onBufferFreed(const wp&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);} diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index c2b5ec4c4d..4aa076e7b2 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -68,7 +68,6 @@ class Surface : public ANativeObjectBase { public: - /* * creates a Surface from the given IGraphicBufferProducer (which concrete * implementation is a BufferQueue). @@ -83,9 +82,15 @@ public: * * the controlledByApp flag indicates that this Surface (producer) is * controlled by the application. This flag is used at connect time. + * + * Pass in the SurfaceControlHandle to store a weak reference to the layer + * that the Surface was created from. This handle can be used to create a + * child surface without using the IGBP to identify the layer. This is used + * for surfaces created by the BlastBufferQueue whose IGBP is created on the + * client and cannot be verified in SF. */ - explicit Surface(const sp& bufferProducer, - bool controlledByApp = false); + explicit Surface(const sp& bufferProducer, bool controlledByApp = false, + const sp& surfaceControlHandle = nullptr); /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this * Surface was created with. Usually it's an error to use the @@ -93,6 +98,8 @@ public: */ sp getIGraphicBufferProducer() const; + sp getSurfaceControlHandle() const { return mSurfaceControlHandle; } + /* convenience function to check that the given surface is non NULL as * well as its IGraphicBufferProducer */ static bool isValid(const sp& surface) { @@ -541,6 +548,11 @@ protected: bool mEnableFrameTimestamps = false; std::unique_ptr mFrameEventHistory; + // Reference to the SurfaceFlinger layer that was used to create this + // surface. This is only populated when the Surface is created from + // a BlastBufferQueue. + sp mSurfaceControlHandle; + bool mReportRemovedBuffers = false; std::vector> mRemovedBuffers; int mMaxBufferCount; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 138f82cd21..fb01dc4ba4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -253,13 +253,13 @@ public: static sp getDefault(); //! Create a surface - sp createSurface(const String8& name, // name of the surface - uint32_t w, // width in pixel - uint32_t h, // height in pixel - PixelFormat format, // pixel-format desired - uint32_t flags = 0, // usage flags - SurfaceControl* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata(), // metadata + sp createSurface(const String8& name, // name of the surface + uint32_t w, // width in pixel + uint32_t h, // height in pixel + PixelFormat format, // pixel-format desired + uint32_t flags = 0, // usage flags + const sp& parentHandle = nullptr, // parentHandle + LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); status_t createSurfaceChecked(const String8& name, // name of the surface @@ -267,9 +267,9 @@ public: uint32_t h, // height in pixel PixelFormat format, // pixel-format desired sp* outSurface, - uint32_t flags = 0, // usage flags - SurfaceControl* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata(), // metadata + uint32_t flags = 0, // usage flags + const sp& parentHandle = nullptr, // parentHandle + LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); //! Create a surface diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h index cc64fd45dd..f7dcbc698d 100644 --- a/libs/gui/include/gui/view/Surface.h +++ b/libs/gui/include/gui/view/Surface.h @@ -21,6 +21,7 @@ #include #include +#include #include namespace android { @@ -43,6 +44,7 @@ class Surface : public Parcelable { String16 name; sp graphicBufferProducer; + sp surfaceControlHandle; virtual status_t writeToParcel(Parcel* parcel) const override; virtual status_t readFromParcel(const Parcel* parcel) override; diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp index d64dfd55be..3e49de6dc8 100644 --- a/libs/gui/view/Surface.cpp +++ b/libs/gui/view/Surface.cpp @@ -45,7 +45,9 @@ status_t Surface::writeToParcel(Parcel* parcel, bool nameAlreadyWritten) const { if (res != OK) return res; } - return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel); + res = IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel); + if (res != OK) return res; + return parcel->writeStrongBinder(surfaceControlHandle); } status_t Surface::readFromParcel(const Parcel* parcel) { @@ -68,6 +70,7 @@ status_t Surface::readFromParcel(const Parcel* parcel, bool nameAlreadyRead) { } graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel); + surfaceControlHandle = parcel->readStrongBinder(); return OK; } diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp index 3dca3916e4..fafb49efba 100644 --- a/services/surfaceflinger/tests/EffectLayer_test.cpp +++ b/services/surfaceflinger/tests/EffectLayer_test.cpp @@ -51,7 +51,7 @@ TEST_F(EffectLayerTest, DefaultEffectLayerHasSolidBlackFill) { sp effectLayer = mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect, - mParentLayer.get()); + mParentLayer->getHandle()); EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; asTransaction([&](Transaction& t) { @@ -72,7 +72,7 @@ TEST_F(EffectLayerTest, EffectLayerWithNoFill) { PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect | ISurfaceComposerClient::eNoColorFill, - mParentLayer.get()); + mParentLayer->getHandle()); EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; asTransaction([&](Transaction& t) { @@ -93,7 +93,7 @@ TEST_F(EffectLayerTest, EffectLayerCanSetColor) { PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect | ISurfaceComposerClient::eNoColorFill, - mParentLayer.get()); + mParentLayer->getHandle()); EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl"; asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index cfec0d2b51..152d2d26f4 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -56,7 +56,7 @@ TEST_F(InvalidHandleTest, createSurfaceInvalidHandle) { auto notSc = makeNotSurfaceControl(); ASSERT_EQ(nullptr, mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0, - notSc.get()) + notSc->getHandle()) .get()); } diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index d4e952aa21..25d3211f6b 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -75,8 +75,9 @@ protected: PixelFormat format, uint32_t flags, SurfaceControl* parent = nullptr, uint32_t* outTransformHint = nullptr) { - auto layer = client->createSurface(String8(name), width, height, format, flags, parent, - LayerMetadata(), outTransformHint); + sp parentHandle = (parent) ? parent->getHandle() : nullptr; + auto layer = client->createSurface(String8(name), width, height, format, flags, + parentHandle, LayerMetadata(), outTransformHint); EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl"; return layer; } diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp index 0cafd001ff..29473f20a4 100644 --- a/services/surfaceflinger/tests/LayerUpdate_test.cpp +++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp @@ -1028,12 +1028,13 @@ TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) { TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) { sp boundlessLayer = mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888, - 0 /* flags */, mFGSurfaceControl.get()); + 0 /* flags */, mFGSurfaceControl->getHandle()); ASSERT_TRUE(boundlessLayer != nullptr); ASSERT_TRUE(boundlessLayer->isValid()); sp colorLayer = mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get()); + ISurfaceComposerClient::eFXSurfaceEffect, + boundlessLayer->getHandle()); ASSERT_TRUE(colorLayer != nullptr); ASSERT_TRUE(colorLayer->isValid()); asTransaction([&](Transaction& t) { diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 1606f2241e..6c654c07e3 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -1469,7 +1469,7 @@ protected: Base::SetUp(); mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); fillSurfaceRGBA8(mChild, LIGHT_GRAY); Base::sFakeComposer->runVSyncAndWait(); @@ -1653,7 +1653,7 @@ protected: sp childNewClient = newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); ASSERT_TRUE(childNewClient != nullptr); ASSERT_TRUE(childNewClient->isValid()); fillSurfaceRGBA8(childNewClient, LIGHT_GRAY); @@ -1732,7 +1732,7 @@ protected: mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); // Show the child layer in a deferred transaction { @@ -1819,7 +1819,7 @@ protected: Base::mComposerClient->createSurface(String8("Child surface"), 0, 0, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect, - Base::mFGSurfaceControl.get()); + Base::mFGSurfaceControl->getHandle()); { TransactionScope ts(*Base::sFakeComposer); ts.setColor(Base::mChild, -- cgit v1.2.3-59-g8ed1b From 4608442db90c07dccc833dbdf1cea78f57c7b96d Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 13 Oct 2020 12:33:42 +0200 Subject: Add shouldBeSeamless to setFrameRate This CL adds a new parameter shouldBeSeamless to the existing setFrameRate APIs. This parameter indicates whether the desired refresh rate should be achieved only seamlessly or also switches with visual interruptions for the user are allowed. The default value of the new parameter is "true". Test: atest RefreshRateConfigsTest Test: atest SetFrameRateTest Test: atest libsurfaceflinger_unittest Test: atest libgui_test Bug: 161776961 Change-Id: I0df16e09f77c8c198fd3733fb581a2aaadfed685 --- include/android/surface_control.h | 38 +++++-- libs/gui/BLASTBufferQueue.cpp | 10 +- libs/gui/ISurfaceComposer.cpp | 16 ++- libs/gui/LayerState.cpp | 4 + libs/gui/Surface.cpp | 8 +- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/LayerState.h | 1 + libs/gui/include/gui/Surface.h | 2 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 +- libs/gui/tests/Surface_test.cpp | 2 +- libs/nativewindow/ANativeWindow.cpp | 13 ++- libs/nativewindow/include/android/native_window.h | 51 ++++++--- libs/nativewindow/include/system/window.h | 4 +- libs/nativewindow/libnativewindow.map.txt | 1 + services/surfaceflinger/Layer.cpp | 11 +- services/surfaceflinger/Layer.h | 11 +- services/surfaceflinger/Scheduler/LayerHistory.cpp | 21 +++- .../surfaceflinger/Scheduler/LayerHistoryV2.cpp | 11 +- services/surfaceflinger/Scheduler/LayerInfoV2.cpp | 4 +- services/surfaceflinger/Scheduler/LayerInfoV2.h | 19 ++-- .../Scheduler/RefreshRateConfigs.cpp | 65 ++++++++++- .../surfaceflinger/Scheduler/RefreshRateConfigs.h | 4 + services/surfaceflinger/Scheduler/StrongTyping.h | 4 + services/surfaceflinger/SurfaceFlinger.cpp | 9 +- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../surfaceflinger/tests/LayerTransactionTest.h | 4 +- .../surfaceflinger/tests/SetFrameRate_test.cpp | 23 ++-- .../tests/TransactionTestHarnesses.h | 8 +- .../tests/unittests/LayerHistoryTestV2.cpp | 2 +- .../tests/unittests/RefreshRateConfigsTest.cpp | 122 ++++++++++++++++++++- .../tests/unittests/RefreshRateStatsTest.cpp | 46 ++++---- 33 files changed, 402 insertions(+), 124 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/include/android/surface_control.h b/include/android/surface_control.h index cbcf6ec5c0..9758c9c8c3 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -410,7 +410,23 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio #if __ANDROID_API__ >= 30 /** - * Sets the intended frame rate for |surface_control|. + * Same as ASurfaceTransaction_setFrameRateWithSeamlessness(transaction, surface_control, + * frameRate, compatibility, true). + * + * See ASurfaceTransaction_setFrameRateWithSeamlessness(). + * + * Available since API level 30. + */ +void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, + ASurfaceControl* surface_control, float frameRate, + int8_t compatibility) __INTRODUCED_IN(30); + +#endif // __ANDROID_API__ >= 30 + +#if __ANDROID_API__ >= 31 + +/** + * Sets the intended frame rate for \a surface_control. * * On devices that are capable of running the display at different refresh rates, the system may * choose a display refresh rate to better match this surface's frame rate. Usage of this API won't @@ -419,24 +435,30 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio * callback timings, and changes to the time interval at which the system releases buffers back to * the application. * - * |frameRate| is the intended frame rate of this surface, in frames per second. 0 is a special + * \param frameRate is the intended frame rate of this surface, in frames per second. 0 is a special * value that indicates the app will accept the system's choice for the display frame rate, which is * the default behavior if this function isn't called. The frameRate param does not need to * be a valid refresh rate for this device's display - e.g., it's fine to pass 30fps to a device * that can only run the display at 60fps. * - * |compatibility| The frame rate compatibility of this surface. The compatibility value may + * \param compatibility The frame rate compatibility of this surface. The compatibility value may * influence the system's choice of display frame rate. To specify a compatibility use the * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. * - * Available since API level 30. + * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * + * Available since API level 31. */ -void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, +void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float frameRate, - int8_t compatibility) __INTRODUCED_IN(30); - -#endif // __ANDROID_API__ >= 30 + int8_t compatibility, bool shouldBeSeamless) + __INTRODUCED_IN(31); +#endif // __ANDROID_API__ >= 31 __END_DECLS #endif // ANDROID_SURFACE_CONTROL_H diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 678613b1ff..ac1c7369b6 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -378,11 +378,11 @@ public: }).detach(); } - status_t setFrameRate(float frameRate, int8_t compatibility) override { + status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) override { if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) { return BAD_VALUE; } - return mBbq->setFrameRate(frameRate, compatibility); + return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); } status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { @@ -392,12 +392,12 @@ public: // TODO: Can we coalesce this with frame updates? Need to confirm // no timing issues. -status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) { +status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, + bool shouldBeSeamless) { std::unique_lock _lock{mMutex}; SurfaceComposerClient::Transaction t; - return t.setFrameRate(mSurfaceControl, frameRate, compatibility) - .apply(); + return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply(); } status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 6f92233935..a9fe5bf319 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1114,7 +1114,7 @@ public: } virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { @@ -1140,6 +1140,12 @@ public: return err; } + err = data.writeBool(shouldBeSeamless); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed writing bool: %s (%d)", strerror(-err), -err); + return err; + } + err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); if (err != NO_ERROR) { ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); @@ -2033,7 +2039,13 @@ status_t BnSurfaceComposer::onTransact( ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); return err; } - status_t result = setFrameRate(surface, frameRate, compatibility); + bool shouldBeSeamless; + err = data.readBool(&shouldBeSeamless); + if (err != NO_ERROR) { + ALOGE("setFrameRate: failed to read bool: %s (%d)", strerror(-err), -err); + return err; + } + status_t result = setFrameRate(surface, frameRate, compatibility, shouldBeSeamless); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 9722f368f4..90999faa78 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -59,6 +59,7 @@ layer_state_t::layer_state_t() frameRateSelectionPriority(-1), frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), + shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0) { matrix.dsdx = matrix.dtdy = 1.0f; @@ -144,6 +145,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority); SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); + SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); @@ -262,6 +264,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &frameRateSelectionPriority); SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); + SAFE_PARCEL(input.readBool, &shouldBeSeamless); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); @@ -521,6 +524,7 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameRateChanged; frameRate = other.frameRate; frameRateCompatibility = other.frameRateCompatibility; + shouldBeSeamless = other.shouldBeSeamless; } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index c1155ab73a..94390aa86c 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1443,7 +1443,8 @@ int Surface::dispatchGetLastQueueDuration(va_list args) { int Surface::dispatchSetFrameRate(va_list args) { float frameRate = static_cast(va_arg(args, double)); int8_t compatibility = static_cast(va_arg(args, int)); - return setFrameRate(frameRate, compatibility); + bool shouldBeSeamless = static_cast(va_arg(args, int)); + return setFrameRate(frameRate, compatibility, shouldBeSeamless); } int Surface::dispatchAddCancelInterceptor(va_list args) { @@ -2279,7 +2280,7 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vectoronBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) { ATRACE_CALL(); ALOGV("Surface::setFrameRate"); @@ -2287,7 +2288,8 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility) { return BAD_VALUE; } - return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility); + return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility, + shouldBeSeamless); } status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 039e9008e8..a822598d82 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1474,7 +1474,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShado } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( - const sp& sc, float frameRate, int8_t compatibility) { + const sp& sc, float frameRate, int8_t compatibility, + bool shouldBeSeamless) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1487,6 +1488,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; s->frameRateCompatibility = compatibility; + s->shouldBeSeamless = shouldBeSeamless; return *this; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 2300e81aa7..7741d8c38a 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -85,7 +85,7 @@ public: void update(const sp& surface, uint32_t width, uint32_t height); void flushShadowQueue() { mFlushShadowQueue = true; } - status_t setFrameRate(float frameRate, int8_t compatibility); + status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); virtual ~BLASTBufferQueue() = default; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 5cd9356449..9e96b79b8c 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -475,7 +475,7 @@ public: * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. */ virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) = 0; + int8_t compatibility, bool shouldBeSeamless) = 0; /* * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index a73d9a68a5..d9f280684f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -218,6 +218,7 @@ struct layer_state_t { // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; int8_t frameRateCompatibility; + bool shouldBeSeamless; // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 4aa076e7b2..82bc5c9efb 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -186,7 +186,7 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - virtual status_t setFrameRate(float frameRate, int8_t compatibility); + virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); protected: diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 73909a30bb..6289c6a3cd 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -524,7 +524,7 @@ public: Transaction& setShadowRadius(const sp& sc, float cornerRadius); Transaction& setFrameRate(const sp& sc, float frameRate, - int8_t compatibility); + int8_t compatibility, bool shouldBeSeamless); // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 0cd3962aa1..2392ae5ccd 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -869,7 +869,7 @@ public: } status_t setFrameRate(const sp& /*surface*/, float /*frameRate*/, - int8_t /*compatibility*/) override { + int8_t /*compatibility*/, bool /*shouldBeSeamless*/) override { return NO_ERROR; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index fd1793b6bc..b406a9c2fe 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -159,10 +159,8 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { } int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { - if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { - return -EINVAL; - } - return native_window_set_frame_rate(window, frameRate, compatibility); + return ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, + /*shouldBeSeamless*/ true); } void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { @@ -172,6 +170,13 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); } +int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, + int8_t compatibility, bool shouldBeSeamless) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return -EINVAL; + } + return native_window_set_frame_rate(window, frameRate, compatibility, shouldBeSeamless); +} /************************************************************************************************** * vndk-stable diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 36aad2eced..deea59b9fb 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -34,6 +34,7 @@ #define ANDROID_NATIVE_WINDOW_H #include +#include #include #include @@ -255,6 +256,31 @@ enum ANativeWindow_FrameRateCompatibility { ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1 }; +/** + * Same as ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, true). + * + * See ANativeWindow_setFrameRateWithSeamlessness(). + * + * Available since API level 30. + */ +int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) + __INTRODUCED_IN(30); + +/** + * Provides a hint to the window that buffers should be preallocated ahead of + * time. Note that the window implementation is not guaranteed to preallocate + * any buffers, for instance if an implementation disallows allocation of new + * buffers, or if there is insufficient memory in the system to preallocate + * additional buffers + * + * Available since API level 30. + */ +void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); + +#endif // __ANDROID_API__ >= 30 + +#if __ANDROID_API__ >= 31 + /** * Sets the intended frame rate for this window. * @@ -271,7 +297,7 @@ enum ANativeWindow_FrameRateCompatibility { * this ANativeWindow is consumed by something other than the system compositor, * e.g. a media codec, this call has no effect. * - * Available since API level 30. + * Available since API level 31. * * \param frameRate The intended frame rate of this window, in frames per * second. 0 is a special value that indicates the app will accept the system's @@ -284,24 +310,19 @@ enum ANativeWindow_FrameRateCompatibility { * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. * + * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * * \return 0 for success, -EINVAL if the window, frame rate, or compatibility * value are invalid. */ -int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) - __INTRODUCED_IN(30); +int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, + int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31); -/** - * Provides a hint to the window that buffers should be preallocated ahead of - * time. Note that the window implementation is not guaranteed to preallocate - * any buffers, for instance if an implementation disallows allocation of new - * buffers, or if there is insufficient memory in the system to preallocate - * additional buffers - * - * Available since API level 30. - */ -void ANativeWindow_tryAllocateBuffers(ANativeWindow* window); - -#endif // __ANDROID_API__ >= 30 +#endif // __ANDROID_API__ >= 31 #ifdef __cplusplus }; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 138e08f490..82d2e661b4 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1018,9 +1018,9 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo } static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, - (int)compatibility); + (int)compatibility, (int)shouldBeSeamless); } static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window, diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 1b5d20dff7..de48ec25dd 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -46,6 +46,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersTransform; ANativeWindow_setDequeueTimeout; # apex # introduced=30 ANativeWindow_setFrameRate; # introduced=30 + ANativeWindow_setFrameRateWithSeamlessness; # introduced=31 ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk ANativeWindow_setUsage; # llndk diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 94819664ce..79e2ad0dbd 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1687,8 +1687,9 @@ void Layer::miniDump(std::string& result, const DisplayDevice& display) const { crop.bottom); if (layerState.frameRate.rate != 0 || layerState.frameRate.type != FrameRateCompatibility::Default) { - StringAppendF(&result, "% 6.2ffps %15s", layerState.frameRate.rate, - frameRateCompatibilityString(layerState.frameRate.type).c_str()); + StringAppendF(&result, "% 6.2ffps %15s seamless=%d", layerState.frameRate.rate, + frameRateCompatibilityString(layerState.frameRate.type).c_str(), + layerState.frameRate.shouldBeSeamless); } else { StringAppendF(&result, " "); } @@ -2750,6 +2751,12 @@ bool Layer::getPrimaryDisplayOnly() const { // --------------------------------------------------------------------------- +std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) { + return stream << "{rate=" << rate.rate + << " type=" << Layer::frameRateCompatibilityString(rate.type) + << " shouldBeSeamless=" << rate.shouldBeSeamless << "}"; +} + }; // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index b1ab9ec306..1a784aa778 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -153,12 +153,15 @@ public: struct FrameRate { float rate; FrameRateCompatibility type; + bool shouldBeSeamless; - FrameRate() : rate(0), type(FrameRateCompatibility::Default) {} - FrameRate(float rate, FrameRateCompatibility type) : rate(rate), type(type) {} + FrameRate() : rate(0), type(FrameRateCompatibility::Default), shouldBeSeamless(true) {} + FrameRate(float rate, FrameRateCompatibility type, bool shouldBeSeamless = true) + : rate(rate), type(type), shouldBeSeamless(shouldBeSeamless) {} bool operator==(const FrameRate& other) const { - return rate == other.rate && type == other.type; + return rate == other.rate && type == other.type && + shouldBeSeamless == other.shouldBeSeamless; } bool operator!=(const FrameRate& other) const { return !(*this == other); } @@ -1126,4 +1129,6 @@ private: const std::vector& getBlurRegions() const; }; +std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); + } // namespace android diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 36433c20ed..28af930bbe 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -125,12 +125,23 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) { return LayerVoteType::NoVote; } }(); - summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f, - layerFocused}); + summary.push_back( + RefreshRateConfigs::LayerRequirement{.name = layer->getName(), + .vote = voteType, + .desiredRefreshRate = frameRate.rate, + .shouldBeSeamless = + frameRate.shouldBeSeamless, + .weight = 1.0f, + .focused = layerFocused}); } else if (recent) { - summary.push_back({layer->getName(), LayerVoteType::Heuristic, - info->getRefreshRate(now), - /* weight */ 1.0f, layerFocused}); + summary.push_back( + RefreshRateConfigs::LayerRequirement{.name = layer->getName(), + .vote = LayerVoteType::Heuristic, + .desiredRefreshRate = + info->getRefreshRate(now), + .shouldBeSeamless = true, + .weight = 1.0f, + .focused = layerFocused}); } if (CC_UNLIKELY(mTraceEnabled)) { diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp index 37e67e17fe..a63ccc1df0 100644 --- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp @@ -130,9 +130,9 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { ALOGV("%s has priority: %d %s focused", strong->getName().c_str(), frameRateSelectionPriority, layerFocused ? "" : "not"); - const auto [type, refreshRate] = info->getRefreshRate(now); + const auto vote = info->getRefreshRateVote(now); // Skip NoVote layer as those don't have any requirements - if (type == LayerHistory::LayerVoteType::NoVote) { + if (vote.type == LayerHistory::LayerVoteType::NoVote) { continue; } @@ -144,10 +144,11 @@ LayerHistoryV2::Summary LayerHistoryV2::summarize(nsecs_t now) { const float layerArea = transformed.getWidth() * transformed.getHeight(); float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f; - summary.push_back({strong->getName(), type, refreshRate, weight, layerFocused}); + summary.push_back({strong->getName(), vote.type, vote.fps, vote.shouldBeSeamless, weight, + layerFocused}); if (CC_UNLIKELY(mTraceEnabled)) { - trace(layer, *info, type, static_cast(std::round(refreshRate))); + trace(layer, *info, vote.type, static_cast(std::round(vote.fps))); } } @@ -178,7 +179,7 @@ void LayerHistoryV2::partitionLayers(nsecs_t now) { if (frameRate.rate > 0 || voteType == LayerVoteType::NoVote) { const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote; - info->setLayerVote(type, frameRate.rate); + info->setLayerVote({type, frameRate.rate, frameRate.shouldBeSeamless}); } else { info->resetLayerVote(); } diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index 44f20d0063..94e7e20251 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -198,10 +198,10 @@ std::optional LayerInfoV2::calculateRefreshRateIfPossible(nsecs_t now) { : std::make_optional(mLastRefreshRate.reported); } -std::pair LayerInfoV2::getRefreshRate(nsecs_t now) { +LayerInfoV2::LayerVote LayerInfoV2::getRefreshRateVote(nsecs_t now) { if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) { ALOGV("%s voted %d ", mName.c_str(), static_cast(mLayerVote.type)); - return {mLayerVote.type, mLayerVote.fps}; + return mLayerVote; } if (isAnimating(now)) { diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h index 33dc66fd19..2305bc3055 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.h +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h @@ -56,6 +56,13 @@ class LayerInfoV2 { friend class LayerHistoryTestV2; public: + // Holds information about the layer vote + struct LayerVote { + LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; + float fps = 0.0f; + bool shouldBeSeamless = true; + }; + static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; } static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) { @@ -76,7 +83,7 @@ public: // Sets an explicit layer vote. This usually comes directly from the application via // ANativeWindow_setFrameRate API - void setLayerVote(LayerHistory::LayerVoteType type, float fps) { mLayerVote = {type, fps}; } + void setLayerVote(LayerVote vote) { mLayerVote = vote; } // Sets the default layer vote. This will be the layer vote after calling to resetLayerVote(). // This is used for layers that called to setLayerVote() and then removed the vote, so that the @@ -84,9 +91,9 @@ public: void setDefaultLayerVote(LayerHistory::LayerVoteType type) { mDefaultVote = type; } // Resets the layer vote to its default. - void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f}; } + void resetLayerVote() { mLayerVote = {mDefaultVote, 0.0f, true}; } - std::pair getRefreshRate(nsecs_t now); + LayerVote getRefreshRateVote(nsecs_t now); // Return the last updated time. If the present time is farther in the future than the // updated time, the updated time is the present time. @@ -130,12 +137,6 @@ private: bool animatingOrInfrequent = false; }; - // Holds information about the layer vote - struct LayerVote { - LayerHistory::LayerVoteType type = LayerHistory::LayerVoteType::Heuristic; - float fps = 0.0f; - }; - // Class to store past calculated refresh rate and determine whether // the refresh rate calculated is consistent with past values class RefreshRateHistory { diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index 150f925fe0..0646c7dfd5 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -31,6 +31,12 @@ namespace android::scheduler { using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; +std::string RefreshRate::toString() const { + return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", + getConfigId().value(), hwcConfig->getId(), getFps(), + hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup()); +} + std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) { switch (vote) { case LayerVoteType::NoVote: @@ -125,7 +131,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( const std::vector& layers, const GlobalSignals& globalSignals, GlobalSignals* outSignalsConsidered) const { ATRACE_CALL(); - ALOGV("getRefreshRateForContent %zu layers", layers.size()); + ALOGV("getBestRefreshRate %zu layers", layers.size()); if (outSignalsConsidered) *outSignalsConsidered = {}; const auto setTouchConsidered = [&] { @@ -148,6 +154,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( int explicitDefaultVoteLayers = 0; int explicitExactOrMultipleVoteLayers = 0; float maxExplicitWeight = 0; + int seamedLayers = 0; for (const auto& layer : layers) { if (layer.vote == LayerVoteType::NoVote) { noVoteLayers++; @@ -162,6 +169,10 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( explicitExactOrMultipleVoteLayers++; maxExplicitWeight = std::max(maxExplicitWeight, layer.weight); } + + if (!layer.shouldBeSeamless) { + seamedLayers++; + } } const bool hasExplicitVoteLayers = @@ -206,6 +217,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( scores.emplace_back(refreshRate, 0.0f); } + const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig); + for (const auto& layer : layers) { ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), layer.weight); @@ -216,6 +229,30 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( auto weight = layer.weight; for (auto i = 0u; i < scores.size(); i++) { + // If there are no layers with shouldBeSeamless=false and the current + // config group is different from the default one, this means a layer with + // shouldBeSeamless=false has just disappeared and we should switch back to + // the default config group. + const bool isSeamlessSwitch = seamedLayers > 0 + ? scores[i].first->getConfigGroup() == mCurrentRefreshRate->getConfigGroup() + : scores[i].first->getConfigGroup() == defaultConfig->getConfigGroup(); + + if (layer.shouldBeSeamless && !isSeamlessSwitch) { + ALOGV("%s (weight %.2f) ignores %s (group=%d) to avoid non-seamless switch." + "Current config = %s", + layer.name.c_str(), weight, scores[i].first->name.c_str(), + scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str()); + continue; + } + + if (!layer.shouldBeSeamless && !isSeamlessSwitch && !layer.focused) { + ALOGV("%s (weight %.2f) ignores %s (group=%d) because it's not focused" + " and the switch is going to be seamed. Current config = %s", + layer.name.c_str(), weight, scores[i].first->name.c_str(), + scores[i].first->getConfigGroup(), mCurrentRefreshRate->toString().c_str()); + continue; + } + bool inPrimaryRange = scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max); if ((primaryRangeIsSingleRate || !inPrimaryRange) && @@ -292,10 +329,13 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate( return 1.0f / iter; }(); + // Slightly prefer seamless switches. + constexpr float kSeamedSwitchPenalty = 0.95f; + const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty; ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(), layerVoteTypeString(layer.vote).c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore); - scores[i].second += weight * layerScore; + scores[i].second += weight * layerScore * seamlessness; continue; } } @@ -367,6 +407,15 @@ const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicy() const { } const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const { + for (auto refreshRate : mPrimaryRefreshRates) { + if (mCurrentRefreshRate->getConfigGroup() == refreshRate->getConfigGroup()) { + return *refreshRate; + } + } + ALOGE("Can't find min refresh rate by policy with the same config group" + " as the current config %s", + mCurrentRefreshRate->toString().c_str()); + // Defaulting to the lowest refresh rate return *mPrimaryRefreshRates.front(); } @@ -376,6 +425,16 @@ const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicy() const { } const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const { + for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) { + const auto& refreshRate = (**it); + if (mCurrentRefreshRate->getConfigGroup() == refreshRate.getConfigGroup()) { + return refreshRate; + } + } + ALOGE("Can't find max refresh rate by policy with the same config group" + " as the current config %s", + mCurrentRefreshRate->toString().c_str()); + // Defaulting to the highest refresh rate return *mPrimaryRefreshRates.back(); } @@ -414,7 +473,7 @@ RefreshRateConfigs::RefreshRateConfigs( const float fps = 1e9f / config->getVsyncPeriod(); mRefreshRates.emplace(configId, std::make_unique(configId, config, - base::StringPrintf("%.0ffps", fps), fps, + base::StringPrintf("%.2ffps", fps), fps, RefreshRate::ConstructorTag(0))); if (configId == currentConfigId) { mCurrentRefreshRate = mRefreshRates.at(configId).get(); diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 8ff92a095c..41e54a7e7b 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -86,6 +86,8 @@ public: bool operator==(const RefreshRate& other) const { return !(*this != other); } + std::string toString() const; + private: friend RefreshRateConfigs; friend class RefreshRateConfigsTest; @@ -216,6 +218,8 @@ public: LayerVoteType vote = LayerVoteType::NoVote; // Layer's desired refresh rate, if applicable. float desiredRefreshRate = 0.0f; + // If a seamless mode switch is required. + bool shouldBeSeamless = true; // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer // would have on choosing the refresh rate. float weight = 0.0f; diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h index e8ca0ba836..6a60257c81 100644 --- a/services/surfaceflinger/Scheduler/StrongTyping.h +++ b/services/surfaceflinger/Scheduler/StrongTyping.h @@ -70,6 +70,10 @@ struct StrongTyping : Ability>... { T const& value() const { return mValue; } T& value() { return mValue; } + friend std::ostream& operator<<(std::ostream& os, const StrongTyping& value) { + return os << value.value(); + } + private: T mValue; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 57c4d52653..28a8e7ac12 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3781,7 +3781,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( "SurfaceFlinger::setClientStateLocked") && layer->setFrameRate(Layer::FrameRate(s.frameRate, Layer::FrameRate::convertCompatibility( - s.frameRateCompatibility)))) { + s.frameRateCompatibility), + s.shouldBeSeamless))) { flags |= eTraversalNeeded; } } @@ -6135,7 +6136,7 @@ const std::unordered_map& SurfaceFlinger::getGenericLayer } status_t SurfaceFlinger::setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) { + int8_t compatibility, bool shouldBeSeamless) { if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) { return BAD_VALUE; } @@ -6148,10 +6149,10 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, ALOGE("Attempt to set frame rate on a layer that no longer exists"); return BAD_VALUE; } - if (layer->setFrameRate( Layer::FrameRate(frameRate, - Layer::FrameRate::convertCompatibility(compatibility)))) { + Layer::FrameRate::convertCompatibility(compatibility), + shouldBeSeamless))) { setTransactionFlags(eTraversalNeeded); } } else { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a821d4473f..9666f145b0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -600,7 +600,7 @@ private: status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility) override; + int8_t compatibility, bool shouldBeSeamless) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; status_t setFrameTimelineVsync(const sp& surface, diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index da71dad2d4..b87c734e27 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -123,7 +123,7 @@ protected: } virtual void fillBufferQueueLayerColor(const sp& layer, const Color& color, - int32_t bufferWidth, int32_t bufferHeight) { + uint32_t bufferWidth, uint32_t bufferHeight) { ANativeWindow_Buffer buffer; ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer)); TransactionUtils::fillANativeWindowBufferColor(buffer, @@ -145,7 +145,7 @@ protected: } void fillLayerColor(uint32_t mLayerType, const sp& layer, const Color& color, - int32_t bufferWidth, int32_t bufferHeight) { + uint32_t bufferWidth, uint32_t bufferHeight) { switch (mLayerType) { case ISurfaceComposerClient::eFXSurfaceBufferQueue: fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight); diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp index 02ba9e290d..d1bed0cc83 100644 --- a/services/surfaceflinger/tests/SetFrameRate_test.cpp +++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - #include #include @@ -50,8 +46,8 @@ protected: } } - const int mLayerWidth = 32; - const int mLayerHeight = 32; + const uint32_t mLayerWidth = 32; + const uint32_t mLayerHeight = 32; sp mLayer; uint32_t mLayerType; }; @@ -59,26 +55,27 @@ protected: TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) { CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue); native_window_set_frame_rate(mLayer->getSurface().get(), 100.f, - ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT); + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); Transaction() - .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) + .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true) .apply(); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); native_window_set_frame_rate(mLayer->getSurface().get(), 300.f, - ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT); + ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED)); } TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) { CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState); Transaction() - .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT) + .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + /* shouldBeSeamless */ true) .apply(); ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN)); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" \ No newline at end of file diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index 01badf4ad9..a361b1e956 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -98,14 +98,14 @@ public: outTransformHint, format); } - void fillLayerColor(const sp& layer, const Color& color, int32_t bufferWidth, - int32_t bufferHeight) { + void fillLayerColor(const sp& layer, const Color& color, uint32_t bufferWidth, + uint32_t bufferHeight) { ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color, bufferWidth, bufferHeight)); } - void fillLayerQuadrant(const sp& layer, int32_t bufferWidth, - int32_t bufferHeight, const Color& topLeft, const Color& topRight, + void fillLayerQuadrant(const sp& layer, uint32_t bufferWidth, + uint32_t bufferHeight, const Color& topLeft, const Color& topRight, const Color& bottomLeft, const Color& bottomRight) { ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer, bufferWidth, bufferHeight, diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index cb376cd7bb..3b50321102 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -78,7 +78,7 @@ protected: for (auto& [weak, info] : history().mLayerInfos) { if (auto strong = weak.promote(); strong && strong.get() == layer) { info->setDefaultLayerVote(vote); - info->setLayerVote(vote, 0); + info->setLayerVote({vote, 0, false}); return; } } diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index 4762fd4b66..df7611043a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -57,6 +57,8 @@ protected: static inline const HwcConfigIndexType HWC_CONFIG_ID_72 = HwcConfigIndexType(2); static inline const HwcConfigIndexType HWC_CONFIG_ID_120 = HwcConfigIndexType(3); static inline const HwcConfigIndexType HWC_CONFIG_ID_30 = HwcConfigIndexType(4); + static inline const HwcConfigIndexType HWC_CONFIG_ID_25 = HwcConfigIndexType(5); + static inline const HwcConfigIndexType HWC_CONFIG_ID_50 = HwcConfigIndexType(6); // Test configs std::shared_ptr mConfig60 = @@ -77,8 +79,16 @@ protected: createConfig(HWC_CONFIG_ID_120, 1, static_cast(1e9f / 120)); std::shared_ptr mConfig30 = createConfig(HWC_CONFIG_ID_30, 0, static_cast(1e9f / 30)); + std::shared_ptr mConfig30DifferentGroup = + createConfig(HWC_CONFIG_ID_30, 1, static_cast(1e9f / 30)); + std::shared_ptr mConfig25DifferentGroup = + createConfig(HWC_CONFIG_ID_25, 1, static_cast(1e9f / 25)); + std::shared_ptr mConfig50 = + createConfig(HWC_CONFIG_ID_50, 0, static_cast(1e9f / 50)); // Test device configurations + // The positions of the configs in the arrays below MUST match their IDs. For example, + // the first config should always be 60Hz, the second 90Hz etc. std::vector> m60OnlyConfigDevice = {mConfig60}; std::vector> m60_90Device = {mConfig60, mConfig90}; std::vector> m60_90DeviceWithDifferentGroups = @@ -104,6 +114,14 @@ protected: {mConfig60, mConfig90, mConfig72, mConfig120DifferentGroup, mConfig30}; std::vector> m30_60_90Device = {mConfig60, mConfig90, mConfig72DifferentGroup, mConfig120DifferentGroup, mConfig30}; + std::vector> m25_30_50_60Device = + {mConfig60, + mConfig90, + mConfig72DifferentGroup, + mConfig120DifferentGroup, + mConfig30DifferentGroup, + mConfig25DifferentGroup, + mConfig50}; // Expected RefreshRate objects RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, "60fps", 60, @@ -292,8 +310,8 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) { /*currentConfigId=*/HWC_CONFIG_ID_60); const auto makeLayerRequirements = [](float refreshRate) -> std::vector { - return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f, - /*focused*/ false}}; + return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*shouldBeSeamless*/ true, + /*weight*/ 1.0f, /*focused*/ false}}; }; EXPECT_EQ(mExpected90Config, @@ -1245,7 +1263,9 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) { auto& layer = layers[0]; layer.vote = LayerVoteType::ExplicitDefault; layer.desiredRefreshRate = 90.0f; + layer.shouldBeSeamless = false; layer.name = "90Hz ExplicitDefault"; + layer.focused = true; ASSERT_EQ(HWC_CONFIG_ID_60, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) @@ -1258,6 +1278,104 @@ TEST_F(RefreshRateConfigsTest, groupSwitching) { ASSERT_EQ(HWC_CONFIG_ID_90, refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) .getConfigId()); + + // Verify that we won't change the group if seamless switch is required. + layer.shouldBeSeamless = true; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + // At this point the default config in the DisplayManager policy with be 60Hz. + // Verify that if the current config is in another group and there are no layers with + // shouldBeSeamless=false we'll go back to the default group. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + layer.desiredRefreshRate = 60.0f; + layer.name = "60Hz ExplicitDefault"; + layer.shouldBeSeamless = true; + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + // If there's a layer with shouldBeSeamless=false, another layer with shouldBeSeamless=true + // can't change the config group. + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90); + auto layer2 = LayerRequirement{.weight = 0.5f}; + layer2.vote = LayerVoteType::ExplicitDefault; + layer2.desiredRefreshRate = 90.0f; + layer2.name = "90Hz ExplicitDefault"; + layer2.shouldBeSeamless = false; + layer2.focused = false; + layers.push_back(layer2); + ASSERT_EQ(HWC_CONFIG_ID_90, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); +} + +TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) { + auto refreshRateConfigs = + std::make_unique(m30_60Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + // Allow group switching. + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + + auto layers = std::vector{LayerRequirement{.weight = 1.0f}}; + auto& layer = layers[0]; + layer.vote = LayerVoteType::ExplicitExactOrMultiple; + layer.desiredRefreshRate = 60.0f; + layer.shouldBeSeamless = false; + layer.name = "60Hz ExplicitExactOrMultiple"; + layer.focused = true; + + ASSERT_EQ(HWC_CONFIG_ID_60, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120); + ASSERT_EQ(HWC_CONFIG_ID_120, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); +} + +TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) { + auto refreshRateConfigs = + std::make_unique(m25_30_50_60Device, + /*currentConfigId=*/HWC_CONFIG_ID_60); + + // Allow group switching. + RefreshRateConfigs::Policy policy; + policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig; + policy.allowGroupSwitching = true; + ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0); + + auto layers = std::vector< + LayerRequirement>{LayerRequirement{.name = "60Hz ExplicitDefault", + .vote = LayerVoteType::ExplicitDefault, + .desiredRefreshRate = 60.0f, + .shouldBeSeamless = false, + .weight = 0.5f, + .focused = false}, + LayerRequirement{.name = "25Hz ExplicitExactOrMultiple", + .vote = LayerVoteType::ExplicitExactOrMultiple, + .desiredRefreshRate = 25.0f, + .shouldBeSeamless = true, + .weight = 1.0f, + .focused = true}}; + auto& seamedLayer = layers[0]; + + ASSERT_EQ(HWC_CONFIG_ID_50, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); + + seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = 30.0f; + refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_30); + + ASSERT_EQ(HWC_CONFIG_ID_25, + refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}) + .getConfigId()); } TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) { diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index de66f8fb41..d0bb9e291a 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -108,7 +108,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(0u, times.count("90fps")); + EXPECT_EQ(0u, times.count("90.00fps")); mRefreshRateStats->setConfigMode(CONFIG_ID_0); mRefreshRateStats->setPowerMode(PowerMode::ON); @@ -116,15 +116,15 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90fps")); - EXPECT_LT(0, times["90fps"]); + ASSERT_EQ(1u, times.count("90.00fps")); + EXPECT_LT(0, times["90.00fps"]); mRefreshRateStats->setPowerMode(PowerMode::DOZE); - int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_0); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; @@ -133,7 +133,7 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); } TEST_F(RefreshRateStatsTest, twoConfigsTest) { @@ -163,53 +163,53 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - ASSERT_EQ(1u, times.count("90fps")); - EXPECT_LT(0, times["90fps"]); + ASSERT_EQ(1u, times.count("90.00fps")); + EXPECT_LT(0, times["90.00fps"]); // When power mode is normal, time for configs updates. mRefreshRateStats->setConfigMode(CONFIG_ID_1); - int ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + int ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - ASSERT_EQ(1u, times.count("60fps")); - EXPECT_LT(0, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + ASSERT_EQ(1u, times.count("60.00fps")); + EXPECT_LT(0, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_0); - int sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + int sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_LT(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_LT(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_1); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + ninety = mRefreshRateStats->getTotalTimes()["90.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_LT(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_LT(sixty, times["60.00fps"]); // Because the power mode is not PowerMode::ON, switching the config // does not update refresh rates that come from the config. mRefreshRateStats->setPowerMode(PowerMode::DOZE); mRefreshRateStats->setConfigMode(CONFIG_ID_0); - sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + sixty = mRefreshRateStats->getTotalTimes()["60.00fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); mRefreshRateStats->setConfigMode(CONFIG_ID_1); screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); times = mRefreshRateStats->getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); - EXPECT_EQ(ninety, times["90fps"]); - EXPECT_EQ(sixty, times["60fps"]); + EXPECT_EQ(ninety, times["90.00fps"]); + EXPECT_EQ(sixty, times["60.00fps"]); } } // namespace } // namespace scheduler -- cgit v1.2.3-59-g8ed1b From 17dde6176332eaaa6e609709f9a8f4231ce7c185 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Mon, 28 Dec 2020 11:39:59 -0800 Subject: BlastBufferQueue: Handle queue to window composer queries When queuing protected buffers, libstagefright queries ANativeWindow to check if the ANativeWindow sends buffers directly to SurfaceFlinger. This check works by verifying the IGBP matches one of the tracked IGBPs in SurfaceFlinger. This does not apply to blast layers since SurfaceFlinger does not create IGBPs and there may not be any IGBP used to submit buffers. To fix this for the blast adapter, we query the blast buffer queue producer to see if it queues to SurfaceFlinger. Bug: b/175904021, b/168917217 Test: atest BlastBufferQueueTest Test: Play protected content via Google Play on AndroidTV Change-Id: Id1affce09742c6b438c7499b525615b8bd294b9a --- libs/gui/BLASTBufferQueue.cpp | 8 ++++++++ libs/gui/Surface.cpp | 4 ++++ libs/gui/tests/BLASTBufferQueue_test.cpp | 13 +++++++++++++ 3 files changed, 25 insertions(+) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index ee5552f20e..89de629442 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -600,6 +600,14 @@ public: return BufferQueueProducer::connect(new AsyncProducerListener(listener), api, producerControlledByApp, output); } + + int query(int what, int* value) override { + if (what == NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) { + *value = 1; + return NO_ERROR; + } + return BufferQueueProducer::query(what, value); + } }; // Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer. diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 94390aa86c..1bba5e4a7d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -985,6 +985,10 @@ int Surface::query(int what, int* value) const { } break; case NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER: { + status_t err = mGraphicBufferProducer->query(what, value); + if (err == NO_ERROR) { + return NO_ERROR; + } if (composerService()->authenticateSurfaceTexture( mGraphicBufferProducer)) { *value = 1; diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 17f8b975a8..170ad87993 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -515,6 +516,18 @@ TEST_F(BLASTBufferQueueTest, CustomProducerListener) { adapter.waitForCallbacks(); } +TEST_F(BLASTBufferQueueTest, QueryNativeWindowQueuesToWindowComposer) { + BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight); + + sp surface = new Surface(adapter.getIGraphicBufferProducer()); + ANativeWindow* nativeWindow = (ANativeWindow*)(surface.get()); + int queuesToNativeWindow = 0; + int err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, + &queuesToNativeWindow); + ASSERT_EQ(NO_ERROR, err); + ASSERT_EQ(queuesToNativeWindow, 1); +} + class BLASTBufferQueueTransformTest : public BLASTBufferQueueTest { public: void test(uint32_t tr) { -- cgit v1.2.3-59-g8ed1b From 78c0ad789e90567ac650fc15ff76e838abe1d12b Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Fri, 7 Feb 2020 14:05:35 -0800 Subject: Surface: add batch dequeue/queue/cancel methods Test: atest libgui_test:SurfaceTest Bug: 113788435 Change-Id: Icd52aeb92e8218b0c201a791ae2a49b79021ac32 --- libs/gui/Surface.cpp | 387 ++++++++++++++++++++++++++++++++++------ libs/gui/include/gui/Surface.h | 25 +++ libs/gui/tests/Surface_test.cpp | 82 +++++++++ 3 files changed, 442 insertions(+), 52 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 94390aa86c..101beff9b1 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -618,29 +618,31 @@ private: std::mutex mMutex; }; +void Surface::getDequeueBufferInputLocked( + IGraphicBufferProducer::DequeueBufferInput* dequeueInput) { + LOG_ALWAYS_FATAL_IF(dequeueInput == nullptr, "input is null"); + + dequeueInput->width = mReqWidth ? mReqWidth : mUserWidth; + dequeueInput->height = mReqHeight ? mReqHeight : mUserHeight; + + dequeueInput->format = mReqFormat; + dequeueInput->usage = mReqUsage; + + dequeueInput->getTimestamps = mEnableFrameTimestamps; +} + int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { ATRACE_CALL(); ALOGV("Surface::dequeueBuffer"); - uint32_t reqWidth; - uint32_t reqHeight; - PixelFormat reqFormat; - uint64_t reqUsage; - bool enableFrameTimestamps; - + IGraphicBufferProducer::DequeueBufferInput dqInput; { Mutex::Autolock lock(mMutex); if (mReportRemovedBuffers) { mRemovedBuffers.clear(); } - reqWidth = mReqWidth ? mReqWidth : mUserWidth; - reqHeight = mReqHeight ? mReqHeight : mUserHeight; - - reqFormat = mReqFormat; - reqUsage = mReqUsage; - - enableFrameTimestamps = mEnableFrameTimestamps; + getDequeueBufferInputLocked(&dqInput); if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot != BufferItem::INVALID_BUFFER_SLOT) { @@ -658,16 +660,17 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { nsecs_t startTime = systemTime(); FrameEventHistoryDelta frameTimestamps; - status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, reqWidth, reqHeight, - reqFormat, reqUsage, &mBufferAge, - enableFrameTimestamps ? &frameTimestamps - : nullptr); + status_t result = mGraphicBufferProducer->dequeueBuffer(&buf, &fence, dqInput.width, + dqInput.height, dqInput.format, + dqInput.usage, &mBufferAge, + dqInput.getTimestamps ? + &frameTimestamps : nullptr); mLastDequeueDuration = systemTime() - startTime; if (result < 0) { ALOGV("dequeueBuffer: IGraphicBufferProducer::dequeueBuffer" "(%d, %d, %d, %#" PRIx64 ") failed: %d", - reqWidth, reqHeight, reqFormat, reqUsage, result); + dqInput.width, dqInput.height, dqInput.format, dqInput.usage, result); return result; } @@ -696,7 +699,7 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { freeAllBuffers(); } - if (enableFrameTimestamps) { + if (dqInput.getTimestamps) { mFrameEventHistory->applyDelta(frameTimestamps); } @@ -739,6 +742,176 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { return OK; } +int Surface::dequeueBuffers(std::vector* buffers) { + using DequeueBufferInput = IGraphicBufferProducer::DequeueBufferInput; + using DequeueBufferOutput = IGraphicBufferProducer::DequeueBufferOutput; + using CancelBufferInput = IGraphicBufferProducer::CancelBufferInput; + using RequestBufferOutput = IGraphicBufferProducer::RequestBufferOutput; + + ATRACE_CALL(); + ALOGV("Surface::dequeueBuffers"); + + if (buffers->size() == 0) { + ALOGE("%s: must dequeue at least 1 buffer!", __FUNCTION__); + return BAD_VALUE; + } + + if (mSharedBufferMode) { + ALOGE("%s: batch operation is not supported in shared buffer mode!", + __FUNCTION__); + return INVALID_OPERATION; + } + + size_t numBufferRequested = buffers->size(); + DequeueBufferInput input; + + { + Mutex::Autolock lock(mMutex); + if (mReportRemovedBuffers) { + mRemovedBuffers.clear(); + } + + getDequeueBufferInputLocked(&input); + } // Drop the lock so that we can still touch the Surface while blocking in IGBP::dequeueBuffers + + std::vector dequeueInput(numBufferRequested, input); + std::vector dequeueOutput; + + nsecs_t startTime = systemTime(); + + status_t result = mGraphicBufferProducer->dequeueBuffers(dequeueInput, &dequeueOutput); + + mLastDequeueDuration = systemTime() - startTime; + + if (result < 0) { + ALOGV("%s: IGraphicBufferProducer::dequeueBuffers" + "(%d, %d, %d, %#" PRIx64 ") failed: %d", + __FUNCTION__, input.width, input.height, input.format, input.usage, result); + return result; + } + + std::vector cancelBufferInputs(numBufferRequested); + std::vector cancelBufferOutputs; + for (size_t i = 0; i < numBufferRequested; i++) { + cancelBufferInputs[i].slot = dequeueOutput[i].slot; + cancelBufferInputs[i].fence = dequeueOutput[i].fence; + } + + for (const auto& output : dequeueOutput) { + if (output.result < 0) { + mGraphicBufferProducer->cancelBuffers(cancelBufferInputs, &cancelBufferOutputs); + ALOGV("%s: IGraphicBufferProducer::dequeueBuffers" + "(%d, %d, %d, %#" PRIx64 ") failed: %d", + __FUNCTION__, input.width, input.height, input.format, input.usage, + output.result); + return output.result; + } + + if (output.slot < 0 || output.slot >= NUM_BUFFER_SLOTS) { + mGraphicBufferProducer->cancelBuffers(cancelBufferInputs, &cancelBufferOutputs); + ALOGE("%s: IGraphicBufferProducer returned invalid slot number %d", + __FUNCTION__, output.slot); + android_errorWriteLog(0x534e4554, "36991414"); // SafetyNet logging + return FAILED_TRANSACTION; + } + + if (input.getTimestamps && !output.timestamps.has_value()) { + mGraphicBufferProducer->cancelBuffers(cancelBufferInputs, &cancelBufferOutputs); + ALOGE("%s: no frame timestamp returns!", __FUNCTION__); + return FAILED_TRANSACTION; + } + + // this should never happen + ALOGE_IF(output.fence == nullptr, + "%s: received null Fence! slot=%d", __FUNCTION__, output.slot); + } + + Mutex::Autolock lock(mMutex); + + // Write this while holding the mutex + mLastDequeueStartTime = startTime; + + std::vector requestBufferSlots; + requestBufferSlots.reserve(numBufferRequested); + // handle release all buffers and request buffers + for (const auto& output : dequeueOutput) { + if (output.result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) { + ALOGV("%s: RELEASE_ALL_BUFFERS during batch operation", __FUNCTION__); + freeAllBuffers(); + break; + } + } + + for (const auto& output : dequeueOutput) { + // Collect slots that needs requesting buffer + sp& gbuf(mSlots[output.slot].buffer); + if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) { + if (mReportRemovedBuffers && (gbuf != nullptr)) { + mRemovedBuffers.push_back(gbuf); + } + requestBufferSlots.push_back(output.slot); + } + } + + // Batch request Buffer + std::vector reqBufferOutput; + if (requestBufferSlots.size() > 0) { + result = mGraphicBufferProducer->requestBuffers(requestBufferSlots, &reqBufferOutput); + if (result != NO_ERROR) { + ALOGE("%s: IGraphicBufferProducer::requestBuffers failed: %d", + __FUNCTION__, result); + mGraphicBufferProducer->cancelBuffers(cancelBufferInputs, &cancelBufferOutputs); + return result; + } + + // Check if we have any single failure + for (size_t i = 0; i < requestBufferSlots.size(); i++) { + if (reqBufferOutput[i].result != OK) { + ALOGE("%s: IGraphicBufferProducer::requestBuffers failed at %zu-th buffer, slot %d", + __FUNCTION__, i, requestBufferSlots[i]); + mGraphicBufferProducer->cancelBuffers(cancelBufferInputs, &cancelBufferOutputs); + return reqBufferOutput[i].result; + } + } + + // Fill request buffer results to mSlots + for (size_t i = 0; i < requestBufferSlots.size(); i++) { + mSlots[requestBufferSlots[i]].buffer = reqBufferOutput[i].buffer; + } + } + + for (size_t batchIdx = 0; batchIdx < numBufferRequested; batchIdx++) { + const auto& output = dequeueOutput[batchIdx]; + int slot = output.slot; + sp& gbuf(mSlots[slot].buffer); + + if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) { + static FenceMonitor hwcReleaseThread("HWC release"); + hwcReleaseThread.queueFence(output.fence); + } + + if (input.getTimestamps) { + mFrameEventHistory->applyDelta(output.timestamps.value()); + } + + if (output.fence->isValid()) { + buffers->at(batchIdx).fenceFd = output.fence->dup(); + if (buffers->at(batchIdx).fenceFd == -1) { + ALOGE("%s: error duping fence: %d", __FUNCTION__, errno); + // dup() should never fail; something is badly wrong. Soldier on + // and hope for the best; the worst that should happen is some + // visible corruption that lasts until the next frame. + } + } else { + buffers->at(batchIdx).fenceFd = -1; + } + + buffers->at(batchIdx).buffer = gbuf.get(); + mDequeuedSlots.insert(slot); + } + return OK; +} + int Surface::cancelBuffer(android_native_buffer_t* buffer, int fenceFd) { ATRACE_CALL(); @@ -769,15 +942,65 @@ int Surface::cancelBuffer(android_native_buffer_t* buffer, return OK; } +int Surface::cancelBuffers(const std::vector& buffers) { + using CancelBufferInput = IGraphicBufferProducer::CancelBufferInput; + ATRACE_CALL(); + ALOGV("Surface::cancelBuffers"); + + if (mSharedBufferMode) { + ALOGE("%s: batch operation is not supported in shared buffer mode!", + __FUNCTION__); + return INVALID_OPERATION; + } + + size_t numBuffers = buffers.size(); + std::vector cancelBufferInputs(numBuffers); + std::vector cancelBufferOutputs; + size_t numBuffersCancelled = 0; + int badSlotResult = 0; + for (size_t i = 0; i < numBuffers; i++) { + int slot = getSlotFromBufferLocked(buffers[i].buffer); + int fenceFd = buffers[i].fenceFd; + if (slot < 0) { + if (fenceFd >= 0) { + close(fenceFd); + } + ALOGE("%s: cannot find slot number for cancelled buffer", __FUNCTION__); + badSlotResult = slot; + } else { + sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); + cancelBufferInputs[numBuffersCancelled].slot = slot; + cancelBufferInputs[numBuffersCancelled++].fence = fence; + } + } + cancelBufferInputs.resize(numBuffersCancelled); + mGraphicBufferProducer->cancelBuffers(cancelBufferInputs, &cancelBufferOutputs); + + + for (size_t i = 0; i < numBuffersCancelled; i++) { + mDequeuedSlots.erase(cancelBufferInputs[i].slot); + } + + if (badSlotResult != 0) { + return badSlotResult; + } + return OK; +} + int Surface::getSlotFromBufferLocked( android_native_buffer_t* buffer) const { + if (buffer == nullptr) { + ALOGE("%s: input buffer is null!", __FUNCTION__); + return BAD_VALUE; + } + for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { if (mSlots[i].buffer != nullptr && mSlots[i].buffer->handle == buffer->handle) { return i; } } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); + ALOGE("%s: unknown buffer: %p", __FUNCTION__, buffer->handle); return BAD_VALUE; } @@ -787,42 +1010,22 @@ int Surface::lockBuffer_DEPRECATED(android_native_buffer_t* buffer __attribute__ return OK; } -int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { - ATRACE_CALL(); - ALOGV("Surface::queueBuffer"); - Mutex::Autolock lock(mMutex); - int64_t timestamp; +void Surface::getQueueBufferInputLocked(android_native_buffer_t* buffer, int fenceFd, + nsecs_t timestamp, IGraphicBufferProducer::QueueBufferInput* out) { bool isAutoTimestamp = false; - if (mTimestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { + if (timestamp == NATIVE_WINDOW_TIMESTAMP_AUTO) { timestamp = systemTime(SYSTEM_TIME_MONOTONIC); isAutoTimestamp = true; ALOGV("Surface::queueBuffer making up timestamp: %.2f ms", timestamp / 1000000.0); - } else { - timestamp = mTimestamp; - } - int i = getSlotFromBufferLocked(buffer); - if (i < 0) { - if (fenceFd >= 0) { - close(fenceFd); - } - return i; - } - if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) { - if (fenceFd >= 0) { - close(fenceFd); - } - return OK; } - // Make sure the crop rectangle is entirely inside the buffer. Rect crop(Rect::EMPTY_RECT); mCrop.intersect(Rect(buffer->width, buffer->height), &crop); sp fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE); - IGraphicBufferProducer::QueueBufferOutput output; IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp, static_cast(mDataSpace), crop, mScalingMode, mTransform ^ mStickyTransform, fence, mStickyTransform, @@ -893,15 +1096,12 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { input.setSurfaceDamage(flippedRegion); } + *out = input; +} - nsecs_t now = systemTime(); - status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); - mLastQueueDuration = systemTime() - now; - if (err != OK) { - ALOGE("queueBuffer: error queuing buffer to SurfaceTexture, %d", err); - } - - mDequeuedSlots.erase(i); +void Surface::onBufferQueuedLocked(int slot, sp fence, + const IGraphicBufferProducer::QueueBufferOutput& output) { + mDequeuedSlots.erase(slot); if (mEnableFrameTimestamps) { mFrameEventHistory->applyDelta(output.frameTimestamps); @@ -935,7 +1135,7 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { mDirtyRegion = Region::INVALID_REGION; } - if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot == i) { + if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot == slot) { mSharedBufferHasBeenQueued = true; } @@ -945,6 +1145,89 @@ int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { static FenceMonitor gpuCompletionThread("GPU completion"); gpuCompletionThread.queueFence(fence); } +} + +int Surface::queueBuffer(android_native_buffer_t* buffer, int fenceFd) { + ATRACE_CALL(); + ALOGV("Surface::queueBuffer"); + Mutex::Autolock lock(mMutex); + + int i = getSlotFromBufferLocked(buffer); + if (i < 0) { + if (fenceFd >= 0) { + close(fenceFd); + } + return i; + } + if (mSharedBufferSlot == i && mSharedBufferHasBeenQueued) { + if (fenceFd >= 0) { + close(fenceFd); + } + return OK; + } + + IGraphicBufferProducer::QueueBufferOutput output; + IGraphicBufferProducer::QueueBufferInput input; + getQueueBufferInputLocked(buffer, fenceFd, mTimestamp, &input); + sp fence = input.fence; + + nsecs_t now = systemTime(); + status_t err = mGraphicBufferProducer->queueBuffer(i, input, &output); + mLastQueueDuration = systemTime() - now; + if (err != OK) { + ALOGE("queueBuffer: error queuing buffer, %d", err); + } + + onBufferQueuedLocked(i, fence, output); + return err; +} + +int Surface::queueBuffers(const std::vector& buffers) { + ATRACE_CALL(); + ALOGV("Surface::queueBuffers"); + Mutex::Autolock lock(mMutex); + + if (mSharedBufferMode) { + ALOGE("%s: batched operation is not supported in shared buffer mode", __FUNCTION__); + return INVALID_OPERATION; + } + + size_t numBuffers = buffers.size(); + std::vector queueBufferInputs(numBuffers); + std::vector queueBufferOutputs; + std::vector bufferSlots(numBuffers, -1); + std::vector> bufferFences(numBuffers); + + for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) { + int i = getSlotFromBufferLocked(buffers[batchIdx].buffer); + if (i < 0) { + if (buffers[batchIdx].fenceFd >= 0) { + close(buffers[batchIdx].fenceFd); + } + return i; + } + bufferSlots[batchIdx] = i; + + IGraphicBufferProducer::QueueBufferInput input; + getQueueBufferInputLocked( + buffers[batchIdx].buffer, buffers[batchIdx].fenceFd, buffers[batchIdx].timestamp, + &input); + bufferFences[batchIdx] = input.fence; + queueBufferInputs[batchIdx] = input; + } + + nsecs_t now = systemTime(); + status_t err = mGraphicBufferProducer->queueBuffers(queueBufferInputs, &queueBufferOutputs); + mLastQueueDuration = systemTime() - now; + if (err != OK) { + ALOGE("%s: error queuing buffer, %d", __FUNCTION__, err); + } + + + for (size_t batchIdx = 0; batchIdx < numBuffers; batchIdx++) { + onBufferQueuedLocked(bufferSlots[batchIdx], bufferFences[batchIdx], + queueBufferOutputs[batchIdx]); + } return err; } diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 82bc5c9efb..43b5dcd60d 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -344,6 +344,23 @@ public: static status_t attachAndQueueBufferWithDataspace(Surface* surface, sp buffer, ui::Dataspace dataspace); + // Batch version of dequeueBuffer, cancelBuffer and queueBuffer + // Note that these batched operations are not supported when shared buffer mode is being used. + struct BatchBuffer { + ANativeWindowBuffer* buffer = nullptr; + int fenceFd = -1; + }; + virtual int dequeueBuffers(std::vector* buffers); + virtual int cancelBuffers(const std::vector& buffers); + + struct BatchQueuedBuffer { + ANativeWindowBuffer* buffer = nullptr; + int fenceFd = -1; + nsecs_t timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + }; + virtual int queueBuffers( + const std::vector& buffers); + protected: enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS }; enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; @@ -373,6 +390,14 @@ protected: void freeAllBuffers(); int getSlotFromBufferLocked(android_native_buffer_t* buffer) const; + void getDequeueBufferInputLocked(IGraphicBufferProducer::DequeueBufferInput* dequeueInput); + + void getQueueBufferInputLocked(android_native_buffer_t* buffer, int fenceFd, nsecs_t timestamp, + IGraphicBufferProducer::QueueBufferInput* out); + + void onBufferQueuedLocked(int slot, sp fence, + const IGraphicBufferProducer::QueueBufferOutput& output); + struct BufferSlot { sp buffer; Region dirtyRegion; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 7761db8815..60a32f0037 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -2024,4 +2024,86 @@ TEST_F(SurfaceTest, DefaultMaxBufferCountSetAndUpdated) { EXPECT_EQ(BufferQueueDefs::NUM_BUFFER_SLOTS, count); } +TEST_F(SurfaceTest, BatchOperations) { + const int BUFFER_COUNT = 16; + const int BATCH_SIZE = 8; + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp cpuConsumer = new CpuConsumer(consumer, 1); + sp surface = new Surface(producer); + sp window(surface); + sp listener = new StubProducerListener(); + + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, /*listener*/listener, + /*reportBufferRemoval*/false)); + + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); + + std::vector buffers(BATCH_SIZE); + + // Batch dequeued buffers can be queued individually + ASSERT_EQ(NO_ERROR, surface->dequeueBuffers(&buffers)); + for (size_t i = 0; i < BATCH_SIZE; i++) { + ANativeWindowBuffer* buffer = buffers[i].buffer; + int fence = buffers[i].fenceFd; + ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence)); + } + + // Batch dequeued buffers can be canceled individually + ASSERT_EQ(NO_ERROR, surface->dequeueBuffers(&buffers)); + for (size_t i = 0; i < BATCH_SIZE; i++) { + ANativeWindowBuffer* buffer = buffers[i].buffer; + int fence = buffers[i].fenceFd; + ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence)); + } + + // Batch dequeued buffers can be batch cancelled + ASSERT_EQ(NO_ERROR, surface->dequeueBuffers(&buffers)); + ASSERT_EQ(NO_ERROR, surface->cancelBuffers(buffers)); + + // Batch dequeued buffers can be batch queued + ASSERT_EQ(NO_ERROR, surface->dequeueBuffers(&buffers)); + std::vector queuedBuffers(BATCH_SIZE); + for (size_t i = 0; i < BATCH_SIZE; i++) { + queuedBuffers[i].buffer = buffers[i].buffer; + queuedBuffers[i].fenceFd = buffers[i].fenceFd; + queuedBuffers[i].timestamp = NATIVE_WINDOW_TIMESTAMP_AUTO; + } + ASSERT_EQ(NO_ERROR, surface->queueBuffers(queuedBuffers)); + + ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); +} + +TEST_F(SurfaceTest, BatchIllegalOperations) { + const int BUFFER_COUNT = 16; + const int BATCH_SIZE = 8; + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp cpuConsumer = new CpuConsumer(consumer, 1); + sp surface = new Surface(producer); + sp window(surface); + sp listener = new StubProducerListener(); + + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, /*listener*/listener, + /*reportBufferRemoval*/false)); + + ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT)); + + std::vector buffers(BATCH_SIZE); + std::vector queuedBuffers(BATCH_SIZE); + + // Batch operations are invalid in shared buffer mode + surface->setSharedBufferMode(true); + ASSERT_EQ(INVALID_OPERATION, surface->dequeueBuffers(&buffers)); + ASSERT_EQ(INVALID_OPERATION, surface->cancelBuffers(buffers)); + ASSERT_EQ(INVALID_OPERATION, surface->queueBuffers(queuedBuffers)); + surface->setSharedBufferMode(false); + + ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From fc434acf530cbde198c8936bf1bc09fad5861031 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 13 Jan 2021 10:28:00 -1000 Subject: Add inputEventId to SurfaceFrame SurfaceFrame will now be aware of the id of the input event that caused the current frame. The flow of input event id is inputflinger -> app -> surfaceflinger. Here, we are adding the 'inputEventId' parameter to the 'setFrameTimelineVsync' call. This call will now be responsible for setting two pieces of information: the vsync id, and the input event id. Since it will no longer be limited to the vsync id, we rename this call to "setFrameTimelineInfo". Once the inputEventId is stored in SurfaceFrame, we will add a binder call to send the frame timing information to inputflinger (separate, future CL). This will allow input to reconstruct the entire sequence of events (at what time was input event getting processed in system_server, app, and surfaceflinger) and will provide the ability to measure end-to-end touch latency. In a separate change, we will also add ATRACE calls to allow manual / script-based latency analysis for local debugging. We will now know which input event is being processed in surfaceflinger. Bug: 169866723 Bug: 129481165 Design doc: https://docs.google.com/document/d/1G3bLaZYSmbe6AKcL-6ZChvrw_B_LXEz29Z6Ed9QoYXY/edit# Test: atest WMShellUnitTests SurfaceParcelable_test libgui_test IPC_test SurfaceFlinger_test Change-Id: If7e0eee82603b38b396b53ad7ced660973efcb50 Merged-In: If7e0eee82603b38b396b53ad7ced660973efcb50 --- libs/gui/Android.bp | 3 + libs/gui/BLASTBufferQueue.cpp | 14 +- libs/gui/FrameTimelineInfo.cpp | 62 +++++ libs/gui/ISurfaceComposer.cpp | 251 ++++++++++----------- libs/gui/ITransactionCompletedListener.cpp | 6 +- libs/gui/LayerState.cpp | 18 +- libs/gui/Surface.cpp | 16 +- libs/gui/SurfaceComposerClient.cpp | 41 ++-- libs/gui/include/gui/BLASTBufferQueue.h | 4 +- libs/gui/include/gui/DisplayEventDispatcher.h | 2 +- libs/gui/include/gui/FrameTimelineInfo.h | 43 ++++ libs/gui/include/gui/ISurfaceComposer.h | 14 +- libs/gui/include/gui/LayerState.h | 4 +- libs/gui/include/gui/Surface.h | 5 +- libs/gui/include/gui/SurfaceComposerClient.h | 13 +- libs/gui/tests/Surface_test.cpp | 6 +- libs/input/android/os/IInputConstants.aidl | 9 + libs/nativewindow/include/system/window.h | 11 +- services/surfaceflinger/BufferQueueLayer.cpp | 14 +- services/surfaceflinger/BufferQueueLayer.h | 6 +- .../surfaceflinger/FrameTimeline/FrameTimeline.cpp | 97 ++++---- .../surfaceflinger/FrameTimeline/FrameTimeline.h | 28 +-- services/surfaceflinger/Layer.cpp | 16 +- services/surfaceflinger/Layer.h | 9 +- services/surfaceflinger/SurfaceFlinger.cpp | 40 ++-- services/surfaceflinger/SurfaceFlinger.h | 18 +- services/surfaceflinger/tests/LayerState_test.cpp | 29 +++ .../tests/unittests/FrameTimelineTest.cpp | 187 +++++++-------- .../tests/unittests/TestableSurfaceFlinger.h | 18 +- .../tests/unittests/TransactionApplicationTest.cpp | 72 +++--- 30 files changed, 589 insertions(+), 467 deletions(-) create mode 100644 libs/gui/FrameTimelineInfo.cpp create mode 100644 libs/gui/include/gui/FrameTimelineInfo.h (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 38ae353a68..fa5044cc16 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { srcs: [ ":framework_native_aidl", + ":inputconstants_aidl", ":libgui_aidl", ":libgui_bufferqueue_sources", @@ -62,6 +63,7 @@ cc_library_shared { "DebugEGLImageTracker.cpp", "DisplayEventDispatcher.cpp", "DisplayEventReceiver.cpp", + "FrameTimelineInfo.cpp", "GLConsumer.cpp", "IConsumerListener.cpp", "IDisplayEventConnection.cpp", @@ -154,6 +156,7 @@ cc_library_static { defaults: ["libgui_bufferqueue-defaults"], srcs: [ + ":inputconstants_aidl", ":libgui_aidl", ":libgui_bufferqueue_sources", ], diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 42d2895950..c62d9ad440 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -370,9 +370,9 @@ void BLASTBufferQueue::processNextBufferLocked(bool useNextTransaction) { } t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber); - if (!mNextFrameTimelineVsyncIdQueue.empty()) { - t->setFrameTimelineVsync(mSurfaceControl, mNextFrameTimelineVsyncIdQueue.front()); - mNextFrameTimelineVsyncIdQueue.pop(); + if (!mNextFrameTimelineInfoQueue.empty()) { + t->setFrameTimelineInfo(mSurfaceControl, mNextFrameTimelineInfoQueue.front()); + mNextFrameTimelineInfoQueue.pop(); } if (mAutoRefresh != bufferItem.mAutoRefresh) { @@ -534,8 +534,8 @@ public: return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); } - status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override { - return mBbq->setFrameTimelineVsync(frameTimelineVsyncId); + status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { + return mBbq->setFrameTimelineInfo(frameTimelineInfo); } }; @@ -549,9 +549,9 @@ status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility, return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply(); } -status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { +status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { std::unique_lock _lock{mMutex}; - mNextFrameTimelineVsyncIdQueue.push(frameTimelineVsyncId); + mNextFrameTimelineInfoQueue.push(frameTimelineInfo); return OK; } diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp new file mode 100644 index 0000000000..f40077403a --- /dev/null +++ b/libs/gui/FrameTimelineInfo.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 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. + */ + +#define LOG_TAG "FrameTimelineInfo" + +#include + +#include +#include +#include +#include + +#include + +using android::os::IInputConstants; + +namespace android { + +status_t FrameTimelineInfo::write(Parcel& output) const { + SAFE_PARCEL(output.writeInt64, vsyncId); + SAFE_PARCEL(output.writeInt32, inputEventId); + return NO_ERROR; +} + +status_t FrameTimelineInfo::read(const Parcel& input) { + SAFE_PARCEL(input.readInt64, &vsyncId); + SAFE_PARCEL(input.readInt32, &inputEventId); + return NO_ERROR; +} + +void FrameTimelineInfo::merge(const FrameTimelineInfo& other) { + // When merging vsync Ids we take the oldest valid one + if (vsyncId != INVALID_VSYNC_ID && other.vsyncId != INVALID_VSYNC_ID) { + if (other.vsyncId > vsyncId) { + vsyncId = other.vsyncId; + inputEventId = other.inputEventId; + } + } else if (vsyncId == INVALID_VSYNC_ID) { + vsyncId = other.vsyncId; + inputEventId = other.inputEventId; + } +} + +void FrameTimelineInfo::clear() { + vsyncId = INVALID_VSYNC_ID; + inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID; +} + +}; // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a8d6832275..f68f3e134e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -68,16 +68,19 @@ public: return interface_cast(reply.readStrongBinder()); } - virtual status_t setTransactionState( - int64_t frameTimelineVsyncId, const Vector& state, - const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& commands, int64_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, - const std::vector& listenerCallbacks, uint64_t transactionId) { + status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& state, + const Vector& displays, uint32_t flags, + const sp& applyToken, const InputWindowCommands& commands, + int64_t desiredPresentTime, bool isAutoTimestamp, + const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + const std::vector& listenerCallbacks, + uint64_t transactionId) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeInt64, frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.write, data); + SAFE_PARCEL(data.writeUint32, static_cast(state.size())); for (const auto& s : state) { SAFE_PARCEL(s.write, data); @@ -108,15 +111,14 @@ public: return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } - virtual void bootFinished() - { + void bootFinished() override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); } - virtual status_t captureDisplay(const DisplayCaptureArgs& args, - const sp& captureListener) { + status_t captureDisplay(const DisplayCaptureArgs& args, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(args.write, data); @@ -125,8 +127,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY, data, &reply); } - virtual status_t captureDisplay(uint64_t displayOrLayerStack, - const sp& captureListener) { + status_t captureDisplay(uint64_t displayOrLayerStack, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(data.writeUint64, displayOrLayerStack); @@ -135,8 +137,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID, data, &reply); } - virtual status_t captureLayers(const LayerCaptureArgs& args, - const sp& captureListener) { + status_t captureLayers(const LayerCaptureArgs& args, + const sp& captureListener) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(args.write, data); @@ -145,9 +147,8 @@ public: return remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); } - virtual bool authenticateSurfaceTexture( - const sp& bufferProducer) const - { + bool authenticateSurfaceTexture( + const sp& bufferProducer) const override { Parcel data, reply; int err = NO_ERROR; err = data.writeInterfaceToken( @@ -180,8 +181,7 @@ public: return result != 0; } - virtual status_t getSupportedFrameTimestamps( - std::vector* outSupported) const { + status_t getSupportedFrameTimestamps(std::vector* outSupported) const override { if (!outSupported) { return UNEXPECTED_NULL; } @@ -224,8 +224,8 @@ public: return NO_ERROR; } - virtual sp createDisplayEventConnection( - VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) { + sp createDisplayEventConnection( + VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override { Parcel data, reply; sp result; int err = data.writeInterfaceToken( @@ -247,8 +247,7 @@ public: return result; } - virtual sp createDisplay(const String8& displayName, bool secure) - { + sp createDisplay(const String8& displayName, bool secure) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t status = data.writeString8(displayName); @@ -272,15 +271,14 @@ public: return display; } - virtual void destroyDisplay(const sp& display) - { + void destroyDisplay(const sp& display) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply); } - virtual std::vector getPhysicalDisplayIds() const { + std::vector getPhysicalDisplayIds() const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) == @@ -297,7 +295,7 @@ public: return {}; } - virtual sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const { + sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeUint64(displayId.value); @@ -305,8 +303,7 @@ public: return reply.readStrongBinder(); } - virtual void setPowerMode(const sp& display, int mode) - { + void setPowerMode(const sp& display, int mode) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -314,7 +311,7 @@ public: remote()->transact(BnSurfaceComposer::SET_POWER_MODE, data, &reply); } - virtual status_t getDisplayState(const sp& display, ui::DisplayState* state) { + status_t getDisplayState(const sp& display, ui::DisplayState* state) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -326,7 +323,7 @@ public: return result; } - virtual status_t getDisplayInfo(const sp& display, DisplayInfo* info) { + status_t getDisplayInfo(const sp& display, DisplayInfo* info) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -336,7 +333,8 @@ public: return reply.read(*info); } - virtual status_t getDisplayConfigs(const sp& display, Vector* configs) { + status_t getDisplayConfigs(const sp& display, + Vector* configs) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -354,9 +352,7 @@ public: return result; } - virtual status_t getDisplayStats(const sp& display, - DisplayStatInfo* stats) - { + status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -370,8 +366,7 @@ public: return result; } - virtual int getActiveConfig(const sp& display) - { + int getActiveConfig(const sp& display) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -379,8 +374,8 @@ public: return reply.readInt32(); } - virtual status_t getDisplayColorModes(const sp& display, - Vector* outColorModes) { + status_t getDisplayColorModes(const sp& display, + Vector* outColorModes) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -409,8 +404,8 @@ public: return result; } - virtual status_t getDisplayNativePrimaries(const sp& display, - ui::DisplayPrimaries& primaries) { + status_t getDisplayNativePrimaries(const sp& display, + ui::DisplayPrimaries& primaries) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -435,7 +430,7 @@ public: return result; } - virtual ColorMode getActiveColorMode(const sp& display) { + ColorMode getActiveColorMode(const sp& display) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -455,8 +450,7 @@ public: return static_cast(reply.readInt32()); } - virtual status_t setActiveColorMode(const sp& display, - ColorMode colorMode) { + status_t setActiveColorMode(const sp& display, ColorMode colorMode) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -481,8 +475,8 @@ public: return static_cast(reply.readInt32()); } - virtual status_t getAutoLowLatencyModeSupport(const sp& display, - bool* outSupport) const { + status_t getAutoLowLatencyModeSupport(const sp& display, + bool* outSupport) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -499,7 +493,7 @@ public: return reply.readBool(outSupport); } - virtual void setAutoLowLatencyMode(const sp& display, bool on) { + void setAutoLowLatencyMode(const sp& display, bool on) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -524,7 +518,8 @@ public: } } - virtual status_t getGameContentTypeSupport(const sp& display, bool* outSupport) const { + status_t getGameContentTypeSupport(const sp& display, + bool* outSupport) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -540,7 +535,7 @@ public: return reply.readBool(outSupport); } - virtual void setGameContentType(const sp& display, bool on) { + void setGameContentType(const sp& display, bool on) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -563,7 +558,7 @@ public: } } - virtual status_t clearAnimationFrameStats() { + status_t clearAnimationFrameStats() override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -578,7 +573,7 @@ public: return reply.readInt32(); } - virtual status_t getAnimationFrameStats(FrameStats* outStats) const { + status_t getAnimationFrameStats(FrameStats* outStats) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply); @@ -586,8 +581,8 @@ public: return reply.readInt32(); } - virtual status_t getHdrCapabilities(const sp& display, - HdrCapabilities* outCapabilities) const { + status_t getHdrCapabilities(const sp& display, + HdrCapabilities* outCapabilities) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t result = data.writeStrongBinder(display); @@ -608,7 +603,7 @@ public: return result; } - virtual status_t enableVSyncInjections(bool enable) { + status_t enableVSyncInjections(bool enable) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -629,7 +624,7 @@ public: return result; } - virtual status_t injectVSync(nsecs_t when) { + status_t injectVSync(nsecs_t when) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -650,7 +645,7 @@ public: return result; } - virtual status_t getLayerDebugInfo(std::vector* outLayers) { + status_t getLayerDebugInfo(std::vector* outLayers) override { if (!outLayers) { return UNEXPECTED_NULL; } @@ -680,10 +675,10 @@ public: return reply.readParcelableVector(outLayers); } - virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace, - ui::PixelFormat* defaultPixelFormat, - ui::Dataspace* wideColorGamutDataspace, - ui::PixelFormat* wideColorGamutPixelFormat) const { + status_t getCompositionPreference(ui::Dataspace* defaultDataspace, + ui::PixelFormat* defaultPixelFormat, + ui::Dataspace* wideColorGamutDataspace, + ui::PixelFormat* wideColorGamutPixelFormat) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -703,7 +698,7 @@ public: return error; } - virtual status_t getColorManagement(bool* outGetColorManagement) const { + status_t getColorManagement(bool* outGetColorManagement) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply); @@ -715,10 +710,10 @@ public: return err; } - virtual status_t getDisplayedContentSamplingAttributes(const sp& display, - ui::PixelFormat* outFormat, - ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const { + status_t getDisplayedContentSamplingAttributes(const sp& display, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const override { if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE; Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -752,8 +747,8 @@ public: return error; } - virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, - uint8_t componentMask, uint64_t maxFrames) { + status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, + uint8_t componentMask, uint64_t maxFrames) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); @@ -766,9 +761,9 @@ public: return result; } - virtual status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const { + status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + uint64_t timestamp, + DisplayedFrameStats* outStats) const override { if (!outStats) return BAD_VALUE; Parcel data, reply; @@ -805,7 +800,7 @@ public: return result; } - virtual status_t getProtectedContentSupport(bool* outSupported) const { + status_t getProtectedContentSupport(bool* outSupported) const override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t error = @@ -817,8 +812,8 @@ public: return error; } - virtual status_t isWideColorDisplay(const sp& token, - bool* outIsWideColorDisplay) const { + status_t isWideColorDisplay(const sp& token, + bool* outIsWideColorDisplay) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -837,9 +832,8 @@ public: return error; } - virtual status_t addRegionSamplingListener(const Rect& samplingArea, - const sp& stopLayerHandle, - const sp& listener) { + status_t addRegionSamplingListener(const Rect& samplingArea, const sp& stopLayerHandle, + const sp& listener) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -868,7 +862,7 @@ public: return error; } - virtual status_t removeRegionSamplingListener(const sp& listener) { + status_t removeRegionSamplingListener(const sp& listener) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -888,12 +882,11 @@ public: return error; } - virtual status_t setDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t defaultConfig, bool allowGroupSwitching, - float primaryRefreshRateMin, - float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) { + status_t setDesiredDisplayConfigSpecs(const sp& displayToken, int32_t defaultConfig, + bool allowGroupSwitching, float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (result != NO_ERROR) { @@ -947,13 +940,12 @@ public: return reply.readInt32(); } - virtual status_t getDesiredDisplayConfigSpecs(const sp& displayToken, - int32_t* outDefaultConfig, - bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) { + status_t getDesiredDisplayConfigSpecs(const sp& displayToken, + int32_t* outDefaultConfig, bool* outAllowGroupSwitching, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) override { if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { @@ -1011,8 +1003,8 @@ public: return reply.readInt32(); } - virtual status_t getDisplayBrightnessSupport(const sp& displayToken, - bool* outSupport) const { + status_t getDisplayBrightnessSupport(const sp& displayToken, + bool* outSupport) const override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1039,7 +1031,7 @@ public: return NO_ERROR; } - virtual status_t setDisplayBrightness(const sp& displayToken, float brightness) { + status_t setDisplayBrightness(const sp& displayToken, float brightness) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1064,7 +1056,7 @@ public: return NO_ERROR; } - virtual status_t notifyPowerBoost(int32_t boostId) { + status_t notifyPowerBoost(int32_t boostId) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1085,8 +1077,8 @@ public: return NO_ERROR; } - virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, float lightRadius) { + status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, + float lightPosY, float lightPosZ, float lightRadius) override { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -1114,8 +1106,8 @@ public: return NO_ERROR; } - virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { + status_t setFrameRate(const sp& surface, float frameRate, + int8_t compatibility, bool shouldBeSeamless) override { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { @@ -1156,7 +1148,7 @@ public: return reply.readInt32(); } - virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) { + status_t acquireFrameRateFlexibilityToken(sp* outToken) override { if (!outToken) return BAD_VALUE; Parcel data, reply; @@ -1191,40 +1183,34 @@ public: return NO_ERROR; } - virtual status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) { + status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) override { Parcel data, reply; status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing interface token: %s (%d)", strerror(-err), - -err); + ALOGE("%s: failed writing interface token: %s (%d)", __func__, strerror(-err), -err); return err; } err = data.writeStrongBinder(IInterface::asBinder(surface)); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing strong binder: %s (%d)", strerror(-err), - -err); + ALOGE("%s: failed writing strong binder: %s (%d)", __func__, strerror(-err), -err); return err; } - err = data.writeInt64(frameTimelineVsyncId); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed writing int64_t: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(frameTimelineInfo.write, data); - err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_VSYNC, data, &reply); + err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_INFO, data, &reply); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to transact: %s (%d)", strerror(-err), err); + ALOGE("%s: failed to transact: %s (%d)", __func__, strerror(-err), err); return err; } return reply.readInt32(); } - virtual status_t addTransactionTraceListener( - const sp& listener) { + status_t addTransactionTraceListener( + const sp& listener) override { Parcel data, reply; SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); @@ -1235,7 +1221,7 @@ public: /** * Get priority of the RenderEngine in surface flinger. */ - virtual int getGPUContextPriority() { + int getGPUContextPriority() override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); status_t err = @@ -1269,8 +1255,9 @@ status_t BnSurfaceComposer::onTransact( case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - int64_t frameTimelineVsyncId; - SAFE_PARCEL(data.readInt64, &frameTimelineVsyncId); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, data); + uint32_t count = 0; SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); Vector state; @@ -1324,10 +1311,10 @@ status_t BnSurfaceComposer::onTransact( uint64_t transactionId = -1; SAFE_PARCEL(data.readUint64, &transactionId); - return setTransactionState(frameTimelineVsyncId, state, displays, stateFlags, - applyToken, inputWindowCommands, desiredPresentTime, - isAutoTimestamp, uncachedBuffer, hasListenerCallbacks, - listenerCallbacks, transactionId); + return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken, + inputWindowCommands, desiredPresentTime, isAutoTimestamp, + uncachedBuffer, hasListenerCallbacks, listenerCallbacks, + transactionId); } case BOOT_FINISHED: { CHECK_INTERFACE(ISurfaceComposer, data, reply); @@ -2078,30 +2065,26 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } - case SET_FRAME_TIMELINE_VSYNC: { + case SET_FRAME_TIMELINE_INFO: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp binder; status_t err = data.readStrongBinder(&binder); if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to read strong binder: %s (%d)", - strerror(-err), -err); + ALOGE("setFrameTimelineInfo: failed to read strong binder: %s (%d)", strerror(-err), + -err); return err; } sp surface = interface_cast(binder); if (!surface) { - ALOGE("setFrameTimelineVsync: failed to cast to IGraphicBufferProducer: %s (%d)", + ALOGE("setFrameTimelineInfo: failed to cast to IGraphicBufferProducer: %s (%d)", strerror(-err), -err); return err; } - int64_t frameTimelineVsyncId; - err = data.readInt64(&frameTimelineVsyncId); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineVsync: failed to read int64_t: %s (%d)", strerror(-err), - -err); - return err; - } - status_t result = setFrameTimelineVsync(surface, frameTimelineVsyncId); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, data); + + status_t result = setFrameTimelineInfo(surface, frameTimelineInfo); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp index 180857185c..0ded9361bf 100644 --- a/libs/gui/ITransactionCompletedListener.cpp +++ b/libs/gui/ITransactionCompletedListener.cpp @@ -92,10 +92,8 @@ status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) { return err; } -JankData::JankData() : - frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID), - jankType(JankType::None) { -} +JankData::JankData() + : frameVsyncId(FrameTimelineInfo::INVALID_VSYNC_ID), jankType(JankType::None) {} status_t JankData::writeToParcel(Parcel* output) const { SAFE_PARCEL(output->writeInt64, frameVsyncId); diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2946aaed37..a4b054a5ff 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -63,7 +63,7 @@ layer_state_t::layer_state_t() shouldBeSeamless(true), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), - frameTimelineVsyncId(ISurfaceComposer::INVALID_VSYNC_ID), + frameTimelineInfo(), autoRefresh(false) { matrix.dsdx = matrix.dtdy = 1.0f; matrix.dsdy = matrix.dtdx = 0.0f; @@ -151,7 +151,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeBool, shouldBeSeamless); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); - SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.write, output); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeUint32, blurRegions.size()); @@ -270,7 +270,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); - SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId); + SAFE_PARCEL(frameTimelineInfo.read, input); SAFE_PARCEL(input.readBool, &autoRefresh); uint32_t numRegions = 0; @@ -537,15 +537,9 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameNumberChanged; frameNumber = other.frameNumber; } - if (other.what & eFrameTimelineVsyncChanged) { - // When merging vsync Ids we take the oldest valid one - if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && - other.frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - frameTimelineVsyncId = std::max(frameTimelineVsyncId, other.frameTimelineVsyncId); - } else if (frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) { - frameTimelineVsyncId = other.frameTimelineVsyncId; - } - what |= eFrameTimelineVsyncChanged; + if (other.what & eFrameTimelineInfoChanged) { + what |= eFrameTimelineInfoChanged; + frameTimelineInfo.merge(other.frameTimelineInfo); } if (other.what & eAutoRefreshChanged) { what |= eAutoRefreshChanged; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e82f0cc9e9..59ad8d28bd 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1496,8 +1496,8 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: res = dispatchGetLastQueuedBuffer(args); break; - case NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC: - res = dispatchSetFrameTimelineVsync(args); + case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: + res = dispatchSetFrameTimelineInfo(args); break; default: res = NAME_NOT_FOUND; @@ -1806,12 +1806,13 @@ int Surface::dispatchGetLastQueuedBuffer(va_list args) { return result; } -int Surface::dispatchSetFrameTimelineVsync(va_list args) { +int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); + auto inputEventId = static_cast(va_arg(args, int32_t)); - ALOGV("Surface::dispatchSetFrameTimelineVsync"); - return setFrameTimelineVsync(frameTimelineVsyncId); + ALOGV("Surface::%s", __func__); + return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); } bool Surface::transformToDisplayInverse() { @@ -2579,9 +2580,8 @@ status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shoul shouldBeSeamless); } -status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) { - return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, - frameTimelineVsyncId); +status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { + return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); } }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 96c099be23..a1bdc033b0 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -396,7 +396,7 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mContainsBuffer(other.mContainsBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), - mFrameTimelineVsyncId(other.mFrameTimelineVsyncId), + mFrameTimelineInfo(other.mFrameTimelineInfo), mApplyToken(other.mApplyToken) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; @@ -427,7 +427,9 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const bool containsBuffer = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); - const int64_t frameTimelineVsyncId = parcel->readInt64(); + FrameTimelineInfo frameTimelineInfo; + SAFE_PARCEL(frameTimelineInfo.read, *parcel); + sp applyToken; parcel->readNullableStrongBinder(&applyToken); size_t count = static_cast(parcel->readUint32()); @@ -502,7 +504,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel mContainsBuffer = containsBuffer; mDesiredPresentTime = desiredPresentTime; mIsAutoTimestamp = isAutoTimestamp; - mFrameTimelineVsyncId = frameTimelineVsyncId; + mFrameTimelineInfo = frameTimelineInfo; mDisplayStates = displayStates; mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; @@ -534,7 +536,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); - parcel->writeInt64(mFrameTimelineVsyncId); + SAFE_PARCEL(mFrameTimelineInfo.write, *parcel); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { @@ -613,13 +615,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mExplicitEarlyWakeupEnd = mExplicitEarlyWakeupEnd || other.mExplicitEarlyWakeupEnd; mApplyToken = other.mApplyToken; - // When merging vsync Ids we take the oldest one - if (mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID && - other.mFrameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - mFrameTimelineVsyncId = std::max(mFrameTimelineVsyncId, other.mFrameTimelineVsyncId); - } else if (mFrameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID) { - mFrameTimelineVsyncId = other.mFrameTimelineVsyncId; - } + mFrameTimelineInfo.merge(other.mFrameTimelineInfo); other.clear(); return *this; @@ -639,7 +635,7 @@ void SurfaceComposerClient::Transaction::clear() { mExplicitEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; - mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + mFrameTimelineInfo.clear(); mApplyToken = nullptr; } @@ -651,9 +647,8 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { uncacheBuffer.id = cacheId; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, {}, {}, 0, applyToken, {}, - systemTime(), true, uncacheBuffer, false, {}, - 0 /* Undefined transactionId */); + sf->setTransactionState(FrameTimelineInfo{}, {}, {}, 0, applyToken, {}, systemTime(), true, + uncacheBuffer, false, {}, 0 /* Undefined transactionId */); } void SurfaceComposerClient::Transaction::cacheBuffers() { @@ -773,7 +768,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { ? mApplyToken : IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken, + sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/, hasListenerCallbacks, listenerCallbacks, mId); @@ -1549,22 +1544,22 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( - int64_t frameTimelineVsyncId) { - mFrameTimelineVsyncId = frameTimelineVsyncId; +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( + const FrameTimelineInfo& frameTimelineInfo) { + mFrameTimelineInfo = frameTimelineInfo; return *this; } -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync( - const sp& sc, int64_t frameTimelineVsyncId) { +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( + const sp& sc, const FrameTimelineInfo& frameTimelineInfo) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } - s->what |= layer_state_t::eFrameTimelineVsyncChanged; - s->frameTimelineVsyncId = frameTimelineVsyncId; + s->what |= layer_state_t::eFrameTimelineInfoChanged; + s->frameTimelineInfo = frameTimelineInfo; return *this; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 7f69bc4244..fa3efe15db 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -92,7 +92,7 @@ public: void flushShadowQueue() { mFlushShadowQueue = true; } status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); - status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); + status_t setFrameTimelineInfo(const FrameTimelineInfo& info); virtual ~BLASTBufferQueue(); @@ -156,7 +156,7 @@ private: // This is only relevant for shared buffer mode. bool mAutoRefresh GUARDED_BY(mMutex) = false; - std::queue mNextFrameTimelineVsyncIdQueue GUARDED_BY(mMutex); + std::queue mNextFrameTimelineInfoQueue GUARDED_BY(mMutex); // Last acquired buffer's scaling mode. This is used to check if we should update the blast // layer size immediately or wait until we get the next buffer. This will support scenarios diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index 5587acf08f..f446dd88ed 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -25,7 +25,7 @@ struct VsyncEventData { // The Vsync Id corresponsing to this vsync event. This will be used to // populate ISurfaceComposer::setFrameTimelineVsync and // SurfaceComposerClient::setFrameTimelineVsync - int64_t id = ISurfaceComposer::INVALID_VSYNC_ID; + int64_t id = FrameTimelineInfo::INVALID_VSYNC_ID; // The deadline in CLOCK_MONOTONIC that the app needs to complete its // frame by (both on the CPU and the GPU) diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/include/gui/FrameTimelineInfo.h new file mode 100644 index 0000000000..3b4c009609 --- /dev/null +++ b/libs/gui/include/gui/FrameTimelineInfo.h @@ -0,0 +1,43 @@ +/* + * 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 + +#include +#include + +namespace android { + +struct FrameTimelineInfo { + // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java + static constexpr int64_t INVALID_VSYNC_ID = -1; + + // The vsync id that was used to start the transaction + int64_t vsyncId = INVALID_VSYNC_ID; + + // The id of the input event that caused this buffer + int32_t inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + + status_t write(Parcel& output) const; + status_t read(const Parcel& input); + + void merge(const FrameTimelineInfo& other); + void clear(); +}; + +} // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 86f3c605ab..81ff6b0d8d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -117,9 +118,6 @@ public: using EventRegistrationFlags = Flags; - // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java - static constexpr int64_t INVALID_VSYNC_ID = -1; - /* * Create a connection with SurfaceFlinger. */ @@ -164,7 +162,7 @@ public: /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual status_t setTransactionState( - int64_t frameTimelineVsyncId, const Vector& state, + const FrameTimelineInfo& frameTimelineInfo, const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, @@ -494,11 +492,11 @@ public: virtual status_t acquireFrameRateFlexibilityToken(sp* outToken) = 0; /* - * Sets the frame timeline vsync id received from choreographer that corresponds to next + * Sets the frame timeline vsync info received from choreographer that corresponds to next * buffer submitted on that surface. */ - virtual status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) = 0; + virtual status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) = 0; /* * Adds a TransactionTraceListener to listen for transaction tracing state updates. @@ -569,7 +567,7 @@ public: SET_GAME_CONTENT_TYPE, SET_FRAME_RATE, ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, - SET_FRAME_TIMELINE_VSYNC, + SET_FRAME_TIMELINE_INFO, ADD_TRANSACTION_TRACE_LISTENER, GET_GPU_CONTEXT_PRIORITY, // Always append new enum to the end. diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index b1305c6607..b3b074ad2f 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -132,7 +132,7 @@ struct layer_state_t { eProducerDisconnect = 0x100'00000000, eFixedTransformHintChanged = 0x200'00000000, eFrameNumberChanged = 0x400'00000000, - eFrameTimelineVsyncChanged = 0x800'00000000, + eFrameTimelineInfoChanged = 0x800'00000000, eBlurRegionsChanged = 0x1000'00000000, eAutoRefreshChanged = 0x2000'00000000, }; @@ -238,7 +238,7 @@ struct layer_state_t { // graphics producer. uint64_t frameNumber; - int64_t frameTimelineVsyncId; + FrameTimelineInfo frameTimelineInfo; // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 43b5dcd60d..b6b5c7ca5e 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -18,6 +18,7 @@ #define ANDROID_GUI_SURFACE_H #include +#include #include #include #include @@ -187,7 +188,7 @@ public: status_t getConsumerUsage(uint64_t* outUsage) const; virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); - virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId); + virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); protected: virtual ~Surface(); @@ -273,7 +274,7 @@ private: int dispatchAddQueueInterceptor(va_list args); int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); - int dispatchSetFrameTimelineVsync(va_list args); + int dispatchSetFrameTimelineInfo(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 11db658de2..bed5c44110 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -385,8 +385,8 @@ public: int64_t mDesiredPresentTime = 0; bool mIsAutoTimestamp = true; - // The vsync Id provided by Choreographer.getVsyncId - int64_t mFrameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + // The vsync id provided by Choreographer.getVsyncId and the input event id + FrameTimelineInfo mFrameTimelineInfo; // If not null, transactions will be queued up using this token otherwise a common token // per process will be used. @@ -546,11 +546,12 @@ public: Transaction& setFixedTransformHint(const sp& sc, int32_t transformHint); // Sets the frame timeline vsync id received from choreographer that corresponds - // to the transaction. - Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId); + // to the transaction, and the input event id that identifies the input event that caused + // the current frame. + Transaction& setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo); // Variant that only applies to a specific SurfaceControl. - Transaction& setFrameTimelineVsync(const sp& sc, - int64_t frameTimelineVsyncId); + Transaction& setFrameTimelineInfo(const sp& sc, + const FrameTimelineInfo& frameTimelineInfo); // Indicates that the consumer should acquire the next frame as soon as it // can and not wait for a frame to become available. This is only relevant diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 63db9a7b96..3f7a5b1785 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -695,7 +695,7 @@ public: void destroyDisplay(const sp& /*display */) override {} std::vector getPhysicalDisplayIds() const override { return {}; } sp getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; } - status_t setTransactionState(int64_t /*frameTimelineVsyncId*/, + status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/, const Vector& /*state*/, const Vector& /*displays*/, uint32_t /*flags*/, const sp& /*applyToken*/, @@ -877,8 +877,8 @@ public: return NO_ERROR; } - status_t setFrameTimelineVsync(const sp& /*surface*/, - int64_t /*frameTimelineVsyncId*/) override { + status_t setFrameTimelineInfo(const sp& /*surface*/, + const FrameTimelineInfo& /*frameTimelineInfo*/) override { return NO_ERROR; } diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl index 6316b59a57..bce0ec8367 100644 --- a/libs/input/android/os/IInputConstants.aidl +++ b/libs/input/android/os/IInputConstants.aidl @@ -28,4 +28,13 @@ interface IInputConstants * to identify apps that are using this flag. */ const long BLOCK_FLAG_SLIPPERY = 157929241; + + // Indicate invalid battery capacity + const int INVALID_BATTERY_CAPACITY = -1; + + /** + * Every input event has an id. This constant value is used when a valid input event id is not + * available. + */ + const int INVALID_INPUT_EVENT_ID = 0; } diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 82d2e661b4..ffe4412b72 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -255,7 +255,7 @@ enum { NATIVE_WINDOW_ALLOCATE_BUFFERS = 45, /* private */ NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ - NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC = 48, /* private */ + NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ // clang-format on }; @@ -1023,10 +1023,11 @@ static inline int native_window_set_frame_rate(struct ANativeWindow* window, flo (int)compatibility, (int)shouldBeSeamless); } -static inline int native_window_set_frame_timeline_vsync(struct ANativeWindow* window, - int64_t frameTimelineVsyncId) { - return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_VSYNC, - frameTimelineVsyncId); +static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, + int64_t frameTimelineVsyncId, + int32_t inputEventId) { + return window->perform(window, NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO, + frameTimelineVsyncId, inputEventId); } // ------------------------------------------------------------------------------------------------ diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 32e6b1098f..52197873c5 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -384,8 +384,8 @@ status_t BufferQueueLayer::updateFrameNumber(nsecs_t latchTime) { return NO_ERROR; } -void BufferQueueLayer::setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) { - mFrameTimelineVsyncId = frameTimelineVsyncId; +void BufferQueueLayer::setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) { + mFrameTimelineInfo = frameTimelineInfo; } // ----------------------------------------------------------------------- @@ -445,9 +445,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId, - mOwnerPid, mOwnerUid, mName, - mName); + mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mName); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems.push_back({item, surfaceFrame}); @@ -485,9 +484,8 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { } auto surfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineVsyncId, - mOwnerPid, mOwnerUid, mName, - mName); + mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mName); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h index 0e8fdbe092..41ff01262e 100644 --- a/services/surfaceflinger/BufferQueueLayer.h +++ b/services/surfaceflinger/BufferQueueLayer.h @@ -101,7 +101,7 @@ private: status_t updateActiveBuffer() override; status_t updateFrameNumber(nsecs_t latchTime) override; - void setFrameTimelineVsyncForBuffer(int64_t frameTimelineVsyncId) override; + void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override; sp createClone() override; @@ -145,10 +145,10 @@ private: sp mContentsChangedListener; - // The last vsync id received on this layer. This will be used when we get + // The last vsync info received on this layer. This will be used when we get // a buffer to correlate the buffer with the vsync id. Can only be accessed // with the SF state lock held. - std::optional mFrameTimelineVsyncId; + FrameTimelineInfo mFrameTimelineInfo; // Keeps track of the time SF latched the last buffer from this layer. // Used in buffer stuffing analysis in FrameTimeline. diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 17d1f3bff7..3743716876 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -275,13 +275,15 @@ int64_t TraceCookieCounter::getCookieForTracing() { return ++mTraceCookie; } -SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName, PredictionState predictionState, +SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, + uid_t ownerUid, std::string layerName, std::string debugName, + PredictionState predictionState, frametimeline::TimelineItem&& predictions, std::shared_ptr timeStats, JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter) - : mToken(token), + : mToken(frameTimelineInfo.vsyncId), + mInputEventId(frameTimelineInfo.inputEventId), mOwnerPid(ownerPid), mOwnerUid(ownerUid), mLayerName(std::move(layerName)), @@ -295,27 +297,27 @@ SurfaceFrame::SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::s mTraceCookieCounter(*traceCookieCounter) {} void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActuals.startTime = actualStartTime; } void SurfaceFrame::setActualQueueTime(nsecs_t actualQueueTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActualQueueTime = actualQueueTime; } void SurfaceFrame::setAcquireFenceTime(nsecs_t acquireFenceTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mActuals.endTime = std::max(acquireFenceTime, mActualQueueTime); } void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mPresentState = presentState; mLastLatchTime = lastLatchTime; } std::optional SurfaceFrame::getJankType() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); if (mActuals.presentTime == 0) { return std::nullopt; } @@ -323,32 +325,32 @@ std::optional SurfaceFrame::getJankType() const { } nsecs_t SurfaceFrame::getBaseTime() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return getMinTime(mPredictionState, mPredictions, mActuals); } TimelineItem SurfaceFrame::getActuals() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mActuals; } SurfaceFrame::PresentState SurfaceFrame::getPresentState() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mPresentState; } FramePresentMetadata SurfaceFrame::getFramePresentMetadata() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mFramePresentMetadata; } FrameReadyMetadata SurfaceFrame::getFrameReadyMetadata() const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); return mFrameReadyMetadata; } void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Layer - %s", mDebugName.c_str()); if (mJankType != JankType::None) { @@ -387,7 +389,7 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); if (mPresentState != PresentState::Presented) { // No need to update dropped buffers return; @@ -479,6 +481,9 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType); } +/** + * TODO(b/178637512): add inputEventId to the perfetto trace. + */ void SurfaceFrame::trace(int64_t displayFrameToken) { using FrameTimelineDataSource = impl::FrameTimeline::FrameTimelineDataSource; @@ -486,12 +491,12 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { bool missingToken = false; // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); - if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { + std::scoped_lock lock(mMutex); + if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid token", mLayerName.c_str()); missingToken = true; return; - } else if (displayFrameToken == ISurfaceComposer::INVALID_VSYNC_ID) { + } else if (displayFrameToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace SurfaceFrame - %s with invalid displayFrameToken", mLayerName.c_str()); missingToken = true; @@ -521,7 +526,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { // Expected timeline end FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast(mPredictions.endTime)); @@ -535,7 +540,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { int64_t actualTimelineCookie = mTraceCookieCounter.getCookieForTracing(); // Actual timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); // Actual start time is not yet available, so use expected start instead @@ -566,7 +571,7 @@ void SurfaceFrame::trace(int64_t displayFrameToken) { }); // Actual timeline end FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(static_cast(mActuals.endTime)); @@ -582,7 +587,7 @@ namespace impl { int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); const int64_t assignedToken = mCurrentToken++; mPredictions[assignedToken] = {systemTime(), predictions}; flushTokens(systemTime()); @@ -590,7 +595,7 @@ int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { } std::optional TokenManager::getPredictionsForToken(int64_t token) const { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); auto predictionsIterator = mPredictions.find(token); if (predictionsIterator != mPredictions.end()) { return predictionsIterator->second.predictions; @@ -634,26 +639,28 @@ void FrameTimeline::registerDataSource() { } std::shared_ptr FrameTimeline::createSurfaceFrameForToken( - std::optional token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName) { + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) { ATRACE_CALL(); - if (!token) { - return std::make_shared(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid, - ownerUid, std::move(layerName), std::move(debugName), + if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem(), mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter); } - std::optional predictions = mTokenManager.getPredictionsForToken(*token); + std::optional predictions = + mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId); if (predictions) { - return std::make_shared(*token, ownerPid, ownerUid, std::move(layerName), - std::move(debugName), PredictionState::Valid, - std::move(*predictions), mTimeStats, - mJankClassificationThresholds, &mTraceCookieCounter); - } - return std::make_shared(*token, ownerPid, ownerUid, std::move(layerName), - std::move(debugName), PredictionState::Expired, - TimelineItem(), mTimeStats, mJankClassificationThresholds, - &mTraceCookieCounter); + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), + PredictionState::Valid, std::move(*predictions), + mTimeStats, mJankClassificationThresholds, + &mTraceCookieCounter); + } + return std::make_shared(frameTimelineInfo, ownerPid, ownerUid, + std::move(layerName), std::move(debugName), + PredictionState::Expired, TimelineItem(), mTimeStats, + mJankClassificationThresholds, &mTraceCookieCounter); } FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr timeStats, @@ -669,13 +676,13 @@ FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr timeStats, void FrameTimeline::addSurfaceFrame(std::shared_ptr surfaceFrame) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame); } void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod, mTokenManager.getPredictionsForToken(token), wakeUpTime); } @@ -683,7 +690,7 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsync void FrameTimeline::setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr& presentFence) { ATRACE_CALL(); - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); mCurrentDisplayFrame->setActualEndTime(sfPresentTime); mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame)); flushPendingPresentFences(); @@ -826,7 +833,7 @@ void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const { // Expected timeline start FrameTimelineDataSource::Trace([&](FrameTimelineDataSource::TraceContext ctx) { auto packet = ctx.NewTracePacket(); - if (mToken == ISurfaceComposer::INVALID_VSYNC_ID) { + if (mToken == FrameTimelineInfo::INVALID_VSYNC_ID) { ALOGD("Cannot trace DisplayFrame with invalid token"); missingToken = true; return; @@ -999,7 +1006,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co } void FrameTimeline::dumpAll(std::string& result) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); StringAppendF(&result, "Number of display frames : %d\n", (int)mDisplayFrames.size()); nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime(); for (size_t i = 0; i < mDisplayFrames.size(); i++) { @@ -1009,7 +1016,7 @@ void FrameTimeline::dumpAll(std::string& result) { } void FrameTimeline::dumpJank(std::string& result) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : mDisplayFrames[0]->getBaseTime(); for (size_t i = 0; i < mDisplayFrames.size(); i++) { mDisplayFrames[i]->dumpJank(result, baseTime, static_cast(i)); @@ -1031,7 +1038,7 @@ void FrameTimeline::parseArgs(const Vector& args, std::string& result) } void FrameTimeline::setMaxDisplayFrames(uint32_t size) { - std::lock_guard lock(mMutex); + std::scoped_lock lock(mMutex); // The size can either increase or decrease, clear everything, to be consistent mDisplayFrames.clear(); diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h index ed38cc6375..54e8efbc92 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h @@ -154,10 +154,10 @@ public: // Only FrameTimeline can construct a SurfaceFrame as it provides Predictions(through // TokenManager), Thresholds and TimeStats pointer. - SurfaceFrame(int64_t token, pid_t ownerPid, uid_t ownerUid, std::string layerName, - std::string debugName, PredictionState predictionState, TimelineItem&& predictions, - std::shared_ptr timeStats, JankClassificationThresholds thresholds, - TraceCookieCounter* traceCookieCounter); + SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName, PredictionState predictionState, + TimelineItem&& predictions, std::shared_ptr timeStats, + JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter); ~SurfaceFrame() = default; // Returns std::nullopt if the frame hasn't been classified yet. @@ -166,6 +166,7 @@ public: // Functions called by SF int64_t getToken() const { return mToken; }; + int32_t getInputEventId() const { return mInputEventId; }; TimelineItem getPredictions() const { return mPredictions; }; // Actual timestamps of the app are set individually at different functions. // Start time (if the app provides) and Queue time are accessible after queueing the frame, @@ -198,6 +199,7 @@ public: private: const int64_t mToken; + const int32_t mInputEventId; const pid_t mOwnerPid; const uid_t mOwnerUid; const std::string mLayerName; @@ -243,10 +245,9 @@ public: // Create a new surface frame, set the predictions based on a token and return it to the caller. // Debug name is the human-readable debugging string for dumpsys. - virtual std::shared_ptr createSurfaceFrameForToken(std::optional token, - pid_t ownerPid, uid_t ownerUid, - std::string layerName, - std::string debugName) = 0; + virtual std::shared_ptr createSurfaceFrameForToken( + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. @@ -279,7 +280,7 @@ namespace impl { class TokenManager : public android::frametimeline::TokenManager { public: - TokenManager() : mCurrentToken(ISurfaceComposer::INVALID_VSYNC_ID + 1) {} + TokenManager() : mCurrentToken(FrameTimelineInfo::INVALID_VSYNC_ID + 1) {} ~TokenManager() = default; int64_t generateTokenForPredictions(TimelineItem&& predictions) override; @@ -353,7 +354,7 @@ public: private: void dump(std::string& result, nsecs_t baseTime) const; - int64_t mToken = ISurfaceComposer::INVALID_VSYNC_ID; + int64_t mToken = FrameTimelineInfo::INVALID_VSYNC_ID; /* Usage of TimelineItem w.r.t SurfaceFlinger * startTime Time when SurfaceFlinger wakes up to handle transactions and buffer updates @@ -393,10 +394,9 @@ public: ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } - std::shared_ptr createSurfaceFrameForToken(std::optional token, - pid_t ownerPid, uid_t ownerUid, - std::string layerName, - std::string debugName) override; + std::shared_ptr createSurfaceFrameForToken( + const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, + std::string layerName, std::string debugName) override; void addSurfaceFrame(std::shared_ptr surfaceFrame) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override; void setSfPresent(nsecs_t sfPresentTime, diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 177a81a7bc..f6440d3843 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -129,7 +129,7 @@ Layer::Layer(const LayerCreationArgs& args) mCurrentState.shadowRadius = 0.f; mCurrentState.treeHasFrameRateVote = false; mCurrentState.fixedTransformHint = ui::Transform::ROT_INVALID; - mCurrentState.frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + mCurrentState.frameTimelineInfo = {}; mCurrentState.postTime = -1; if (args.flags & ISurfaceComposerClient::eNoColorFill) { @@ -907,14 +907,10 @@ bool Layer::applyPendingStates(State* stateToCommit) { } if (stateUpdateAvailable) { - const auto vsyncId = - stateToCommit->frameTimelineVsyncId == ISurfaceComposer::INVALID_VSYNC_ID - ? std::nullopt - : std::make_optional(stateToCommit->frameTimelineVsyncId); - mSurfaceFrame = - mFlinger->mFrameTimeline->createSurfaceFrameForToken(vsyncId, mOwnerPid, mOwnerUid, - mName, mTransactionName); + mFlinger->mFrameTimeline + ->createSurfaceFrameForToken(stateToCommit->frameTimelineInfo, mOwnerPid, + mOwnerUid, mName, mTransactionName); mSurfaceFrame->setActualQueueTime(stateToCommit->postTime); // For transactions we set the acquire fence time to the post time as we // don't have a buffer. For BufferStateLayer it is overridden in @@ -1491,8 +1487,8 @@ bool Layer::setFrameRate(FrameRate frameRate) { return true; } -void Layer::setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime) { - mCurrentState.frameTimelineVsyncId = frameTimelineVsyncId; +void Layer::setFrameTimelineInfoForTransaction(const FrameTimelineInfo& info, nsecs_t postTime) { + mCurrentState.frameTimelineInfo = info; mCurrentState.postTime = postTime; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 357c4a4dee..0660a4a998 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -304,8 +304,8 @@ public: // a fixed transform hint is not set. ui::Transform::RotationFlags fixedTransformHint; - // The vsync id that was used to start the transaction - int64_t frameTimelineVsyncId; + // The vsync info that was used to start the transaction + FrameTimelineInfo frameTimelineInfo; // When the transaction was posted nsecs_t postTime; @@ -869,8 +869,9 @@ public: bool setFrameRate(FrameRate); - virtual void setFrameTimelineVsyncForBuffer(int64_t /*frameTimelineVsyncId*/) {} - void setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime); + virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {} + void setFrameTimelineInfoForTransaction(const FrameTimelineInfo& frameTimelineInfo, + nsecs_t postTime); // Creates a new handle each time, so we only expect // this to be called once. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 27df232472..8d448e0910 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3287,7 +3287,7 @@ bool SurfaceFlinger::flushTransactionQueues() { break; } transactions.push_back(transaction); - applyTransactionState(transaction.frameTimelineVsyncId, transaction.states, + applyTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, mPendingInputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, transaction.buffer, @@ -3367,7 +3367,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t } status_t SurfaceFlinger::setTransactionState( - int64_t frameTimelineVsyncId, const Vector& states, + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, @@ -3420,7 +3420,7 @@ status_t SurfaceFlinger::setTransactionState( // if the transaction contains a buffer. if (!transactionIsReadyToBeApplied(isAutoTimestamp, desiredPresentTime, states, true) || pendingTransactions) { - mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags, + mTransactionQueues[applyToken].emplace(frameTimelineInfo, states, displays, flags, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, @@ -3429,7 +3429,7 @@ status_t SurfaceFlinger::setTransactionState( return NO_ERROR; } - applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands, + applyTransactionState(frameTimelineInfo, states, displays, flags, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged, hasListenerCallbacks, listenerCallbacks, originPid, originUid, transactionId, /*isMainThread*/ false); @@ -3437,7 +3437,7 @@ status_t SurfaceFlinger::setTransactionState( } void SurfaceFlinger::applyTransactionState( - int64_t frameTimelineVsyncId, const Vector& states, + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime, @@ -3478,9 +3478,9 @@ void SurfaceFlinger::applyTransactionState( uint32_t clientStateFlags = 0; for (const ComposerState& state : states) { clientStateFlags |= - setClientStateLocked(frameTimelineVsyncId, state, desiredPresentTime, - isAutoTimestamp, postTime, privileged, - listenerCallbacksWithSurfaces, originPid, originUid); + setClientStateLocked(frameTimelineInfo, 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(), @@ -3658,7 +3658,7 @@ bool SurfaceFlinger::callingThreadHasUnscopedSurfaceFlingerAccess(bool usePermis } uint32_t SurfaceFlinger::setClientStateLocked( - int64_t frameTimelineVsyncId, const ComposerState& composerState, + const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks, int originPid, int originUid) { @@ -3916,10 +3916,10 @@ uint32_t SurfaceFlinger::setClientStateLocked( flags |= eTraversalNeeded; } } - if (what & layer_state_t::eFrameTimelineVsyncChanged) { - layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime); - } else if (frameTimelineVsyncId != ISurfaceComposer::INVALID_VSYNC_ID) { - layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime); + if (what & layer_state_t::eFrameTimelineInfoChanged) { + layer->setFrameTimelineInfoForTransaction(s.frameTimelineInfo, postTime); + } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + layer->setFrameTimelineInfoForTransaction(frameTimelineInfo, postTime); } if (what & layer_state_t::eFixedTransformHintChanged) { if (layer->setFixedTransformHint(s.fixedTransformHint)) { @@ -4255,7 +4255,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr, + setTransactionState(FrameTimelineInfo{}, state, displays, 0, nullptr, mPendingInputWindowCommands, systemTime(), true, {}, false, {}, 0 /* Undefined transactionId */); @@ -5006,7 +5006,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CAPTURE_LAYERS: case CAPTURE_DISPLAY: case SET_DISPLAY_BRIGHTNESS: - case SET_FRAME_TIMELINE_VSYNC: + case SET_FRAME_TIMELINE_INFO: // This is not sensitive information, so should not require permission control. case GET_GPU_CONTEXT_PRIORITY: { return OK; @@ -6374,21 +6374,21 @@ void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() { })); } -status_t SurfaceFlinger::setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) { +status_t SurfaceFlinger::setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) { Mutex::Autolock lock(mStateLock); if (!authenticateSurfaceTextureLocked(surface)) { - ALOGE("Attempt to set frame timeline vsync on an unrecognized IGraphicBufferProducer"); + ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer"); return BAD_VALUE; } sp layer = (static_cast(surface.get()))->getLayer(); if (layer == nullptr) { - ALOGE("Attempt to set frame timeline vsync on a layer that no longer exists"); + ALOGE("Attempt to set frame timeline info on a layer that no longer exists"); return BAD_VALUE; } - layer->setFrameTimelineVsyncForBuffer(frameTimelineVsyncId); + layer->setFrameTimelineInfoForBuffer(frameTimelineInfo); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 50d6099698..323ed40e36 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -343,7 +343,7 @@ protected: virtual ~SurfaceFlinger(); virtual uint32_t setClientStateLocked( - int64_t frameTimelineVsyncId, const ComposerState& composerState, + const FrameTimelineInfo& info, const ComposerState& composerState, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged, std::unordered_set& listenerCallbacks, int originPid, int originUid) REQUIRES(mStateLock); @@ -435,14 +435,15 @@ private: }; struct TransactionState { - TransactionState(int64_t frameTimelineVsyncId, const Vector& composerStates, + TransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& composerStates, const Vector& displayStates, uint32_t transactionFlags, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged, bool hasListenerCallbacks, std::vector listenerCallbacks, int originPid, int originUid, uint64_t transactionId) - : frameTimelineVsyncId(frameTimelineVsyncId), + : frameTimelineInfo(frameTimelineInfo), states(composerStates), displays(displayStates), flags(transactionFlags), @@ -457,7 +458,7 @@ private: originUid(originUid), id(transactionId) {} - int64_t frameTimelineVsyncId; + FrameTimelineInfo frameTimelineInfo; Vector states; Vector displays; uint32_t flags; @@ -522,7 +523,8 @@ private: void destroyDisplay(const sp& displayToken) override; std::vector getPhysicalDisplayIds() const override; sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override; - status_t setTransactionState(int64_t frameTimelineVsyncId, const Vector& state, + status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, + const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, @@ -608,8 +610,8 @@ private: int8_t compatibility, bool shouldBeSeamless) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; - status_t setFrameTimelineVsync(const sp& surface, - int64_t frameTimelineVsyncId) override; + status_t setFrameTimelineInfo(const sp& surface, + const FrameTimelineInfo& frameTimelineInfo) override; status_t addTransactionTraceListener( const sp& listener) override; @@ -727,7 +729,7 @@ private: /* * Transactions */ - void applyTransactionState(int64_t frameTimelineVsyncId, const Vector& state, + void applyTransactionState(const FrameTimelineInfo& info, const Vector& state, const Vector& displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, diff --git a/services/surfaceflinger/tests/LayerState_test.cpp b/services/surfaceflinger/tests/LayerState_test.cpp index 93d5f2f8ec..80dbd1b889 100644 --- a/services/surfaceflinger/tests/LayerState_test.cpp +++ b/services/surfaceflinger/tests/LayerState_test.cpp @@ -106,5 +106,34 @@ TEST(LayerStateTest, ParcellingScreenCaptureResults) { ASSERT_EQ(results.result, results2.result); } +/** + * Parcel a layer_state_t struct, and then unparcel. Ensure that the object that was parceled + * matches the object that's unparceled. + */ +TEST(LayerStateTest, ParcelUnparcelLayerStateT) { + layer_state_t input; + input.frameTimelineInfo.vsyncId = 1; + input.frameTimelineInfo.inputEventId = 2; + Parcel p; + input.write(p); + layer_state_t output; + p.setDataPosition(0); + output.read(p); + ASSERT_EQ(input.frameTimelineInfo.vsyncId, output.frameTimelineInfo.vsyncId); + ASSERT_EQ(input.frameTimelineInfo.inputEventId, output.frameTimelineInfo.inputEventId); +} + +TEST(LayerStateTest, LayerStateMerge_SelectsValidInputEvent) { + layer_state_t layer1; + layer1.frameTimelineInfo.inputEventId = android::os::IInputConstants::INVALID_INPUT_EVENT_ID; + layer_state_t layer2; + layer2.frameTimelineInfo.inputEventId = 1; + layer2.what |= layer_state_t::eFrameTimelineInfoChanged; + + layer1.merge(layer2); + + ASSERT_EQ(1, layer1.frameTimelineInfo.inputEventId); +} + } // namespace test } // namespace android diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index e2584e266d..6e9f09bdaa 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -14,9 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wextra" #include "gmock/gmock-spec-builders.h" #include "mock/MockTimeStats.h" @@ -177,16 +174,17 @@ static const std::string sLayerNameTwo = "layer2"; static constexpr const uid_t sUidOne = 0; static constexpr pid_t sPidOne = 10; static constexpr pid_t sPidTwo = 20; +static constexpr int32_t sInputEventId = 5; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); - EXPECT_EQ(getPredictions().size(), 1); + EXPECT_EQ(getPredictions().size(), 1u); flushTokens(systemTime() + maxTokenRetentionTime); int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30}); std::optional predictions = mTokenManager->getPredictionsForToken(token1); // token1 should have expired - EXPECT_EQ(getPredictions().size(), 1); + EXPECT_EQ(getPredictions().size(), 1u); EXPECT_EQ(predictions.has_value(), false); predictions = mTokenManager->getPredictionsForToken(token2); @@ -194,16 +192,16 @@ TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_getOwnerPidReturnsCorrectPid) { - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); - auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidTwo, sUidOne, + auto surfaceFrame2 = mFrameTimeline->createSurfaceFrameForToken({}, sPidTwo, sUidOne, sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame1->getOwnerPid(), sPidOne); EXPECT_EQ(surfaceFrame2->getOwnerPid(), sPidTwo); } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::None); } @@ -211,21 +209,33 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); flushTokens(systemTime() + maxTokenRetentionTime); - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired); } TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid); EXPECT_EQ(compareTimelineItems(surfaceFrame->getPredictions(), TimelineItem(10, 20, 30)), true); } +TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { + int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + constexpr int32_t inputEventId = 1; + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); + + EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId()); +} + TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)); @@ -234,8 +244,9 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, 11); @@ -264,11 +275,11 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameTwo, sLayerNameTwo); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameTwo, sLayerNameTwo); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -288,8 +299,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame3 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame3->setPresentState(SurfaceFrame::PresentState::Dropped); mFrameTimeline->addSurfaceFrame(surfaceFrame3); @@ -320,8 +331,9 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, + sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -341,8 +353,8 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -356,18 +368,18 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceAfterQueue) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue"); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue", + "acquireFenceAfterQueue"); surfaceFrame->setActualQueueTime(123); surfaceFrame->setAcquireFenceTime(456); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); } TEST_F(FrameTimelineTest, surfaceFrameEndTimeAcquireFenceBeforeQueue) { - auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, 0, - "acquireFenceAfterQueue", - "acquireFenceAfterQueue"); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, 0, "acquireFenceAfterQueue", + "acquireFenceAfterQueue"); surfaceFrame->setActualQueueTime(456); surfaceFrame->setAcquireFenceTime(123); EXPECT_EQ(surfaceFrame->getActuals().endTime, 456); @@ -383,8 +395,8 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Size shouldn't exceed maxDisplayFrames - 64 for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -395,15 +407,15 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Increase the size to 256 mFrameTimeline->setMaxDisplayFrames(256); - EXPECT_EQ(*maxDisplayFrames, 256); + EXPECT_EQ(*maxDisplayFrames, 256u); // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -414,15 +426,15 @@ TEST_F(FrameTimelineTest, setMaxDisplayFramesSetsSizeProperly) { // Shrink the size to 128 mFrameTimeline->setMaxDisplayFrames(128); - EXPECT_EQ(*maxDisplayFrames, 128); + EXPECT_EQ(*maxDisplayFrames, 128u); // Global increment EXPECT_CALL(*mTimeStats, incrementJankyFrames(testing::_)) .Times(static_cast(*maxDisplayFrames + 10)); for (size_t i = 0; i < *maxDisplayFrames + 10; i++) { auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, + sLayerNameOne); int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30}); mFrameTimeline->setSfWakeUp(sfToken, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); @@ -449,8 +461,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { std::chrono::duration_cast(56ms).count(), std::chrono::duration_cast(60ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), 11); @@ -478,8 +490,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { std::chrono::duration_cast(56ms).count(), std::chrono::duration_cast(60ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast(52ms).count(), 30); @@ -507,8 +519,8 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { std::chrono::duration_cast(86ms).count(), std::chrono::duration_cast(90ms).count()}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, @@ -542,8 +554,9 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token1, 20, 11); @@ -558,7 +571,7 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { mFrameTimeline->setSfPresent(55, presentFence2); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 0); + EXPECT_EQ(packets.size(), 0u); } TEST_F(FrameTimelineTest, tracing_sanityTest) { @@ -573,8 +586,9 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(token1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + auto surfaceFrame1 = + mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, + sLayerNameOne, sLayerNameOne); // Set up the display frame mFrameTimeline->setSfWakeUp(token2, 20, 11); @@ -594,7 +608,7 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); // Display Frame 1 has 8 packets - 4 from DisplayFrame and 4 from SurfaceFrame. - EXPECT_EQ(packets.size(), 8); + EXPECT_EQ(packets.size(), 8u); } TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) { @@ -622,7 +636,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_invalidTokenDoesNotEmitTracePacket) tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 0); + EXPECT_EQ(packets.size(), 0u); } TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) { @@ -635,7 +649,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); - auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken(std::nullopt, sPidOne, sUidOne, + auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); // Set up the display frame @@ -657,7 +671,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_invalidTokenDoesNotEmitTracePacket) auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); // Display Frame 1 has 4 packets (SurfaceFrame shouldn't be traced since it has an invalid // token). - EXPECT_EQ(packets.size(), 4); + EXPECT_EQ(packets.size(), 4u); } void validateTraceEvent(const ProtoExpectedDisplayFrameStart& received, @@ -791,12 +805,12 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 4); + EXPECT_EQ(packets.size(), 4u); // Packet - 0 : ExpectedDisplayFrameStart const auto& packet0 = packets[0]; ASSERT_TRUE(packet0.has_timestamp()); - EXPECT_EQ(packet0.timestamp(), 10); + EXPECT_EQ(packet0.timestamp(), 10u); ASSERT_TRUE(packet0.has_frame_timeline_event()); const auto& event0 = packet0.frame_timeline_event(); @@ -807,7 +821,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 1 : FrameEnd (ExpectedDisplayFrame) const auto& packet1 = packets[1]; ASSERT_TRUE(packet1.has_timestamp()); - EXPECT_EQ(packet1.timestamp(), 25); + EXPECT_EQ(packet1.timestamp(), 25u); ASSERT_TRUE(packet1.has_frame_timeline_event()); const auto& event1 = packet1.frame_timeline_event(); @@ -818,7 +832,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 2 : ActualDisplayFrameStart const auto& packet2 = packets[2]; ASSERT_TRUE(packet2.has_timestamp()); - EXPECT_EQ(packet2.timestamp(), 20); + EXPECT_EQ(packet2.timestamp(), 20u); ASSERT_TRUE(packet2.has_frame_timeline_event()); const auto& event2 = packet2.frame_timeline_event(); @@ -829,7 +843,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_emitsValidTracePacket) { // Packet - 3 : FrameEnd (ActualDisplayFrame) const auto& packet3 = packets[3]; ASSERT_TRUE(packet3.has_timestamp()); - EXPECT_EQ(packet3.timestamp(), 26); + EXPECT_EQ(packet3.timestamp(), 26u); ASSERT_TRUE(packet3.has_frame_timeline_event()); const auto& event3 = packet3.frame_timeline_event(); @@ -853,8 +867,8 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { int64_t displayFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setActualStartTime(0); surfaceFrame1->setActualQueueTime(15); surfaceFrame1->setAcquireFenceTime(20); @@ -904,12 +918,12 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { tracingSession->StopBlocking(); auto packets = readFrameTimelinePacketsBlocking(tracingSession.get()); - EXPECT_EQ(packets.size(), 8); + EXPECT_EQ(packets.size(), 8u); // Packet - 4 : ExpectedSurfaceFrameStart const auto& packet4 = packets[4]; ASSERT_TRUE(packet4.has_timestamp()); - EXPECT_EQ(packet4.timestamp(), 10); + EXPECT_EQ(packet4.timestamp(), 10u); ASSERT_TRUE(packet4.has_frame_timeline_event()); const auto& event4 = packet4.frame_timeline_event(); @@ -920,7 +934,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 5 : FrameEnd (ExpectedSurfaceFrame) const auto& packet5 = packets[5]; ASSERT_TRUE(packet5.has_timestamp()); - EXPECT_EQ(packet5.timestamp(), 25); + EXPECT_EQ(packet5.timestamp(), 25u); ASSERT_TRUE(packet5.has_frame_timeline_event()); const auto& event5 = packet5.frame_timeline_event(); @@ -931,7 +945,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 6 : ActualSurfaceFrameStart const auto& packet6 = packets[6]; ASSERT_TRUE(packet6.has_timestamp()); - EXPECT_EQ(packet6.timestamp(), 10); + EXPECT_EQ(packet6.timestamp(), 10u); ASSERT_TRUE(packet6.has_frame_timeline_event()); const auto& event6 = packet6.frame_timeline_event(); @@ -942,7 +956,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { // Packet - 7 : FrameEnd (ActualSurfaceFrame) const auto& packet7 = packets[7]; ASSERT_TRUE(packet7.has_timestamp()); - EXPECT_EQ(packet7.timestamp(), 20); + EXPECT_EQ(packet7.timestamp(), 20u); ASSERT_TRUE(packet7.has_frame_timeline_event()); const auto& event7 = packet7.frame_timeline_event(); @@ -961,8 +975,8 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -1126,8 +1140,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1145,8 +1159,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1199,8 +1213,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1218,8 +1232,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1270,8 +1284,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 42, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1316,8 +1330,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(26); mFrameTimeline->setSfWakeUp(sfToken1, 32, 11); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1335,8 +1349,8 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken2, 43, 11); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1390,8 +1404,8 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 56, 60}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 116, 120}); auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken1, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, 30); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1409,8 +1423,8 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken(surfaceFrameToken2, sPidOne, sUidOne, - sLayerNameOne, sLayerNameOne); + mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, + sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame2->setAcquireFenceTime(84); mFrameTimeline->setSfWakeUp(sfToken2, 112, 30); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); @@ -1456,6 +1470,3 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli JankType::AppDeadlineMissed | JankType::BufferStuffing); } } // namespace android::frametimeline - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra" \ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 2701f472aa..8ca052f710 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -368,16 +368,14 @@ public: auto& getTransactionQueue() { return mFlinger->mTransactionQueues; } - auto setTransactionState(int64_t frameTimelineVsyncId, const Vector& states, - const Vector& displays, uint32_t flags, - const sp& applyToken, - const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, bool isAutoTimestamp, - const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, - std::vector& listenerCallbacks, - uint64_t transactionId) { - return mFlinger->setTransactionState(frameTimelineVsyncId, states, displays, flags, - applyToken, inputWindowCommands, desiredPresentTime, + auto setTransactionState( + const FrameTimelineInfo& frameTimelineInfo, const Vector& states, + const Vector& displays, uint32_t flags, const sp& applyToken, + const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, + bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, + std::vector& listenerCallbacks, uint64_t transactionId) { + return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, + inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, hasListenerCallbacks, listenerCallbacks, transactionId); } diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 06275c6b5b..6d2f672bce 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" -#pragma clang diagnostic ignored "-Wextra" #undef LOG_TAG #define LOG_TAG "CompositionTest" @@ -100,43 +96,44 @@ public: InputWindowCommands inputWindowCommands; int64_t desiredPresentTime = 0; bool isAutoTimestamp = true; - int64_t frameTimelineVsyncId = ISurfaceComposer::INVALID_VSYNC_ID; + FrameTimelineInfo frameTimelineInfo; client_cache_t uncacheBuffer; - int64_t id = -1; + uint64_t id = static_cast(-1); + static_assert(0xffffffffffffffff == static_cast(-1)); }; void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) { - EXPECT_EQ(0, info.states.size()); - EXPECT_EQ(0, state.states.size()); + EXPECT_EQ(0u, info.states.size()); + EXPECT_EQ(0u, state.states.size()); - EXPECT_EQ(0, info.displays.size()); - EXPECT_EQ(0, state.displays.size()); + EXPECT_EQ(0u, info.displays.size()); + EXPECT_EQ(0u, state.displays.size()); EXPECT_EQ(info.flags, state.flags); EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime); } void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows, int64_t desiredPresentTime, bool isAutoTimestamp, - int64_t frameTimelineVsyncId) { + const FrameTimelineInfo& frameTimelineInfo) { mTransactionNumber++; transaction.flags |= flags; // ISurfaceComposer::eSynchronous; transaction.inputWindowCommands.syncInputWindows = syncInputWindows; transaction.desiredPresentTime = desiredPresentTime; transaction.isAutoTimestamp = isAutoTimestamp; - transaction.frameTimelineVsyncId = frameTimelineVsyncId; + transaction.frameTimelineInfo = frameTimelineInfo; } void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime())); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - ISurfaceComposer::INVALID_VSYNC_ID); + FrameTimelineInfo{}); nsecs_t applicationTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, @@ -155,11 +152,11 @@ public: EXPECT_LE(returnedTime, applicationTime + s2ns(5)); } auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(0, transactionQueue.size()); + EXPECT_EQ(0u, transactionQueue.size()); } void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -170,10 +167,9 @@ public: .WillOnce(Return(time + nsecs_t(5 * 1e8))); TransactionInfo transaction; setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ time + s2ns(1), false, - ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineVsyncId, transaction.states, + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, transaction.applyToken, transaction.inputWindowCommands, transaction.desiredPresentTime, transaction.isAutoTimestamp, @@ -184,11 +180,11 @@ public: EXPECT_LE(returnedTime, applicationSentTime + s2ns(5)); // This transaction should have been placed on the transaction queue auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1, transactionQueue.size()); + EXPECT_EQ(1u, transactionQueue.size()); } void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction nsecs_t time = systemTime(); EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -197,18 +193,17 @@ public: // transaction that should go on the pending thread TransactionInfo transactionA; setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ time + s2ns(1), false, - ISurfaceComposer::INVALID_VSYNC_ID); + /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); // transaction that would not have gone on the pending thread if not // blocked TransactionInfo transactionB; setupSingle(transactionB, flags, syncInputWindows, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - ISurfaceComposer::INVALID_VSYNC_ID); + FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, @@ -221,7 +216,7 @@ public: EXPECT_LE(systemTime(), applicationSentTime + s2ns(5)); applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionB.frameTimelineVsyncId, transactionB.states, + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, transactionB.displays, transactionB.flags, transactionB.applyToken, transactionB.inputWindowCommands, transactionB.desiredPresentTime, transactionB.isAutoTimestamp, @@ -240,10 +235,10 @@ public: // check that there is one binder on the pending queue. auto transactionQueue = mFlinger.getTransactionQueue(); - EXPECT_EQ(1, transactionQueue.size()); + EXPECT_EQ(1u, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); - EXPECT_EQ(2, transactionStates.size()); + EXPECT_EQ(2u, transactionStates.size()); auto& transactionStateA = transactionStates.front(); transactionStates.pop(); @@ -258,7 +253,7 @@ public: }; TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { - ASSERT_EQ(0, mFlinger.getTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); // called in SurfaceFlinger::signalTransaction EXPECT_CALL(*mMessageQueue, invalidate()).Times(1); @@ -268,18 +263,18 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { .WillOnce(Return(s2ns(2))); TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ s2ns(1), false, ISurfaceComposer::INVALID_VSYNC_ID); - mFlinger.setTransactionState(transactionA.frameTimelineVsyncId, transactionA.states, + /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, transactionA.isAutoTimestamp, transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, transactionA.id); auto& transactionQueue = mFlinger.getTransactionQueue(); - ASSERT_EQ(1, transactionQueue.size()); + ASSERT_EQ(1u, transactionQueue.size()); auto& [applyToken, transactionStates] = *(transactionQueue.begin()); - ASSERT_EQ(1, transactionStates.size()); + ASSERT_EQ(1u, transactionStates.size()); auto& transactionState = transactionStates.front(); checkEqual(transactionA, transactionState); @@ -289,8 +284,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // different process) to re-query and reset the cached expected present time TransactionInfo empty; empty.applyToken = sp(); - mFlinger.setTransactionState(empty.frameTimelineVsyncId, empty.states, empty.displays, - empty.flags, empty.applyToken, empty.inputWindowCommands, + mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags, + empty.applyToken, empty.inputWindowCommands, empty.desiredPresentTime, empty.isAutoTimestamp, empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id); @@ -298,7 +293,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // passed mFlinger.flushTransactionQueues(); - EXPECT_EQ(0, transactionQueue.size()); + EXPECT_EQ(0u, transactionQueue.size()); } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) { @@ -343,6 +338,3 @@ TEST_F(TransactionApplicationTest, FromHandle) { EXPECT_EQ(nullptr, ret.promote().get()); } } // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion -Wextra" -- cgit v1.2.3-59-g8ed1b From 564f9deb6d5c9ee27bd6a84f7c6e4544ad9e174a Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Wed, 3 Feb 2021 18:34:33 -0800 Subject: SurfaceFlinger: expose vsync id extra buffers Expose a function for clients to call and query the number of extra buffers needed when vsync id is passed with the buffer. Test: launch an app and observe systrace Test: SF unit tests Bug: 178148035 Change-Id: Icbeec66073feeae9768f0dcc45831b26144ab6f6 --- libs/gui/ISurfaceComposer.cpp | 22 ++++++++++++++++++++ libs/gui/Surface.cpp | 15 ++++++++++++++ libs/gui/include/gui/ISurfaceComposer.h | 19 +++++++++++++++++ libs/gui/include/gui/Surface.h | 2 ++ libs/gui/tests/Surface_test.cpp | 2 ++ libs/nativewindow/include/system/window.h | 6 ++++++ services/surfaceflinger/SurfaceFlinger.cpp | 24 ++++++++++++++++++++-- services/surfaceflinger/SurfaceFlinger.h | 5 +++++ .../tests/unittests/SchedulerTest.cpp | 12 +++++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 5 +++++ 10 files changed, 110 insertions(+), 2 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f68f3e134e..e3aaf6dfd7 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1232,6 +1232,18 @@ public: } return reply.readInt32(); } + + status_t getExtraBufferCount(int* extraBuffers) const override { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + status_t err = remote()->transact(BnSurfaceComposer::GET_EXTRA_BUFFER_COUNT, data, &reply); + if (err != NO_ERROR) { + ALOGE("getExtraBufferCount failed to read data: %s (%d)", strerror(-err), err); + return err; + } + + return reply.readInt32(extraBuffers); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -2101,6 +2113,16 @@ status_t BnSurfaceComposer::onTransact( SAFE_PARCEL(reply->writeInt32, priority); return NO_ERROR; } + case GET_EXTRA_BUFFER_COUNT: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + int extraBuffers = 0; + int err = getExtraBufferCount(&extraBuffers); + if (err != NO_ERROR) { + return err; + } + SAFE_PARCEL(reply->writeInt32, extraBuffers); + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 59ad8d28bd..07fc0694d6 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1499,6 +1499,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: res = dispatchSetFrameTimelineInfo(args); break; + case NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT: + res = dispatchGetExtraBufferCount(args); + break; default: res = NAME_NOT_FOUND; break; @@ -1815,6 +1818,14 @@ int Surface::dispatchSetFrameTimelineInfo(va_list args) { return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); } +int Surface::dispatchGetExtraBufferCount(va_list args) { + ATRACE_CALL(); + auto extraBuffers = static_cast(va_arg(args, int*)); + + ALOGV("Surface::dispatchGetExtraBufferCount"); + return getExtraBufferCount(extraBuffers); +} + bool Surface::transformToDisplayInverse() { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -2584,4 +2595,8 @@ status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInf return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); } +status_t Surface::getExtraBufferCount(int* extraBuffers) const { + return composerService()->getExtraBufferCount(extraBuffers); +} + }; // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 81ff6b0d8d..e56670d72a 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -508,6 +508,24 @@ public: * Gets priority of the RenderEngine in SurfaceFlinger. */ virtual int getGPUContextPriority() = 0; + + /** + * Gets the extra buffers a client would need to allocate if it passes + * the Choreographer#getVsyncId with its buffers. + * + * When Choreographer#getVsyncId is passed to SurfaceFlinger, it is used + * as an indication of when to latch the buffer. SurfaceFlinger will make + * sure that it will give the app at least the time configured as the + * 'appDuration' before trying to latch the buffer. + * + * The total buffers needed for a given configuration is basically the + * numbers of vsyncs a single buffer is used across the stack. For the default + * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger + * and 1 vsync by the display. The extra buffers are calculated as the + * number of additional buffers on top of the 3 buffers already allocated + * by the app. + */ + virtual status_t getExtraBufferCount(int* extraBuffers) const = 0; }; // ---------------------------------------------------------------------------- @@ -570,6 +588,7 @@ public: SET_FRAME_TIMELINE_INFO, ADD_TRANSACTION_TRACE_LISTENER, GET_GPU_CONTEXT_PRIORITY, + GET_EXTRA_BUFFER_COUNT, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index b6b5c7ca5e..58812214d2 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -189,6 +189,7 @@ public: virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); + virtual status_t getExtraBufferCount(int* extraBuffers) const; protected: virtual ~Surface(); @@ -275,6 +276,7 @@ private: int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); int dispatchSetFrameTimelineInfo(va_list args); + int dispatchGetExtraBufferCount(va_list args); bool transformToDisplayInverse(); protected: diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 3f7a5b1785..bbf090651d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -889,6 +889,8 @@ public: int getGPUContextPriority() override { return 0; }; + status_t getExtraBufferCount(int* /*extraBuffers*/) const override { return NO_ERROR; } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index ffe4412b72..7aa2cf4404 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -256,6 +256,7 @@ enum { NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ + NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT = 49, /* private */ // clang-format on }; @@ -1030,6 +1031,11 @@ static inline int native_window_set_frame_timeline_info(struct ANativeWindow* wi frameTimelineVsyncId, inputEventId); } +static inline int native_window_get_extra_buffer_count( + struct ANativeWindow* window, int* extraBuffers) { + return window->perform(window, NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT, extraBuffers); +} + // ------------------------------------------------------------------------------------------------ // Candidates for APEX visibility // These functions are planned to be made stable for APEX modules, but have not diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index cf7d1e14a5..d57d0da5ca 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5030,8 +5030,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CAPTURE_DISPLAY: case SET_DISPLAY_BRIGHTNESS: case SET_FRAME_TIMELINE_INFO: - // This is not sensitive information, so should not require permission control. - case GET_GPU_CONTEXT_PRIORITY: { + case GET_GPU_CONTEXT_PRIORITY: + case GET_EXTRA_BUFFER_COUNT: { + // This is not sensitive information, so should not require permission control. return OK; } case ADD_REGION_SAMPLING_LISTENER: @@ -6458,6 +6459,25 @@ int SurfaceFlinger::getGPUContextPriority() { return getRenderEngine().getContextPriority(); } +int SurfaceFlinger::calculateExtraBufferCount(Fps maxSupportedRefreshRate, + std::chrono::nanoseconds presentLatency) { + auto pipelineDepth = presentLatency.count() / maxSupportedRefreshRate.getPeriodNsecs(); + if (presentLatency.count() % maxSupportedRefreshRate.getPeriodNsecs()) { + pipelineDepth++; + } + return std::max(0ll, pipelineDepth - 2); +} + +status_t SurfaceFlinger::getExtraBufferCount(int* extraBuffers) const { + const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max; + const auto vsyncConfig = + mVsyncConfiguration->getConfigsForRefreshRate(maxSupportedRefreshRate).late; + const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration; + + *extraBuffers = calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency); + return NO_ERROR; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 400345f684..49308a49f4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -623,6 +623,8 @@ private: int getGPUContextPriority() override; + status_t getExtraBufferCount(int* extraBuffers) const override; + // Implements IBinder::DeathRecipient. void binderDied(const wp& who) override; @@ -1053,6 +1055,9 @@ private: return std::nullopt; } + static int calculateExtraBufferCount(Fps maxSupportedRefreshRate, + std::chrono::nanoseconds presentLatency); + sp mStartPropertySetThread; surfaceflinger::Factory& mFactory; diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index e688e10e14..510b620612 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -69,6 +69,8 @@ protected: Scheduler::ConnectionHandle mConnectionHandle; mock::EventThread* mEventThread; sp mEventThreadConnection; + + TestableSurfaceFlinger mFlinger; }; SchedulerTest::SchedulerTest() { @@ -187,4 +189,14 @@ TEST_F(SchedulerTest, onNonPrimaryDisplayConfigChanged_invalidParameters) { EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0); } +TEST_F(SchedulerTest, calculateExtraBufferCount) { + EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 30ms)); + EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(90), 30ms)); + EXPECT_EQ(2, mFlinger.calculateExtraBufferCount(Fps(120), 30ms)); + + EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(60), 40ms)); + + EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 10ms)); +} + } // namespace android diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 3787c436a0..6b145b00fd 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -391,6 +391,11 @@ public: auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); } + auto calculateExtraBufferCount(Fps maxSupportedRefreshRate, + std::chrono::nanoseconds presentLatency) const { + return SurfaceFlinger::calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency); + } + /* ------------------------------------------------------------------------ * Read-only access to private data to assert post-conditions. */ -- cgit v1.2.3-59-g8ed1b From 228f46b5b9c3eac674aceb579a718cd459165f2e Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Thu, 28 Jan 2021 21:11:45 +0100 Subject: Introduce DynamicDisplayInfo In this CL we introduce the getDynamicDisplayInfo call on ISurfaceComposer which replaces the existing - getDisplayModes - getActiveDisplayMode - getColorModes - getActiveColorMode - getHdrCapabilities This way all display properties can be queried atomically. The current DisplayInfo class is moved to the androd::ui namespace and it's renamed to StaticDisplayInfo. ui::DisplayMode is now LightFlattenable and the mode ID is int32_t instead of size_t in order to prevent serialization problems. Additionally we add the ID field to ui::DisplayMode. This way we no longer need the supported display IDs to be from 0 to N-1. Bug: 159590486 Bug: 180539476 Test: presubmit, manually test that device boots Change-Id: I52b170913ce47cb5df2e8417e6cc95d395df1fda --- cmds/surfacereplayer/replayer/Replayer.cpp | 1 - include/input/TouchVideoFrame.h | 2 +- include/ui/DisplayInfo.h | 1 - include/ui/StaticDisplayInfo.h | 1 + libs/gui/ISurfaceComposer.cpp | 220 ++++----------------- libs/gui/Surface.cpp | 14 +- libs/gui/SurfaceComposerClient.cpp | 59 +++--- libs/gui/SurfaceControl.cpp | 2 +- libs/gui/include/gui/ISurfaceComposer.h | 70 +++---- libs/gui/include/gui/SurfaceComposerClient.h | 35 ++-- libs/gui/tests/Surface_test.cpp | 24 +-- libs/nativedisplay/ADisplay.cpp | 41 ++-- libs/nativedisplay/include/apex/display.h | 5 + libs/ui/Android.bp | 4 +- libs/ui/DisplayInfo.cpp | 54 ----- libs/ui/DisplayMode.cpp | 69 +++++++ libs/ui/DynamicDisplayInfo.cpp | 66 +++++++ libs/ui/HdrCapabilities.cpp | 4 - libs/ui/StaticDisplayInfo.cpp | 54 +++++ libs/ui/include/ui/DisplayInfo.h | 42 ---- libs/ui/include/ui/DisplayMode.h | 17 +- libs/ui/include/ui/DynamicDisplayInfo.h | 52 +++++ libs/ui/include/ui/HdrCapabilities.h | 6 - libs/ui/include/ui/StaticDisplayInfo.h | 41 ++++ libs/ui/include_vndk/ui/DisplayInfo.h | 1 - libs/ui/include_vndk/ui/StaticDisplayInfo.h | 1 + .../compositionengine/DisplayCreationArgs.h | 4 +- .../CompositionEngine/src/Display.cpp | 3 +- .../CompositionEngine/tests/DisplayTest.cpp | 10 +- .../CompositionEngine/tests/MockHWComposer.h | 2 +- services/surfaceflinger/DisplayDevice.cpp | 4 +- services/surfaceflinger/DisplayDevice.h | 10 +- .../surfaceflinger/DisplayHardware/DisplayMode.h | 5 +- services/surfaceflinger/DisplayHardware/HWC2.cpp | 7 +- services/surfaceflinger/DisplayHardware/HWC2.h | 6 +- .../surfaceflinger/DisplayHardware/HWComposer.cpp | 10 +- .../surfaceflinger/DisplayHardware/HWComposer.h | 4 +- .../Scheduler/RefreshRateConfigs.cpp | 6 +- services/surfaceflinger/SurfaceFlinger.cpp | 202 +++++++------------ services/surfaceflinger/SurfaceFlinger.h | 27 +-- services/surfaceflinger/tests/Credentials_test.cpp | 26 +-- .../surfaceflinger/tests/DisplayConfigs_test.cpp | 14 +- .../tests/fakehwc/SFFakeHwc_test.cpp | 26 ++- .../tests/unittests/CompositionTest.cpp | 4 +- .../tests/unittests/DisplayTransactionTest.cpp | 8 +- .../unittests/DisplayTransactionTestHelpers.h | 13 +- .../tests/unittests/TestableSurfaceFlinger.h | 2 +- 47 files changed, 623 insertions(+), 656 deletions(-) delete mode 120000 include/ui/DisplayInfo.h create mode 120000 include/ui/StaticDisplayInfo.h delete mode 100644 libs/ui/DisplayInfo.cpp create mode 100644 libs/ui/DisplayMode.cpp create mode 100644 libs/ui/DynamicDisplayInfo.cpp create mode 100644 libs/ui/StaticDisplayInfo.cpp delete mode 100644 libs/ui/include/ui/DisplayInfo.h create mode 100644 libs/ui/include/ui/DynamicDisplayInfo.h create mode 100644 libs/ui/include/ui/StaticDisplayInfo.h delete mode 120000 libs/ui/include_vndk/ui/DisplayInfo.h create mode 120000 libs/ui/include_vndk/ui/StaticDisplayInfo.h (limited to 'libs/gui/Surface.cpp') diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp index 58d6582e0b..3c53c025ff 100644 --- a/cmds/surfacereplayer/replayer/Replayer.cpp +++ b/cmds/surfacereplayer/replayer/Replayer.cpp @@ -28,7 +28,6 @@ #include #include -#include #include #include #include diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h index 4fa2f86dc1..eda628e233 100644 --- a/include/input/TouchVideoFrame.h +++ b/include/input/TouchVideoFrame.h @@ -57,7 +57,7 @@ public: /** * Rotate the video frame. - * The rotation value is an enum from ui/DisplayInfo.h + * The rotation value is an enum from ui/Rotation.h */ void rotate(int32_t orientation); diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h deleted file mode 120000 index 9a195eaed4..0000000000 --- a/include/ui/DisplayInfo.h +++ /dev/null @@ -1 +0,0 @@ -../../libs/ui/include/ui/DisplayInfo.h \ No newline at end of file diff --git a/include/ui/StaticDisplayInfo.h b/include/ui/StaticDisplayInfo.h new file mode 120000 index 0000000000..c58aae3020 --- /dev/null +++ b/include/ui/StaticDisplayInfo.h @@ -0,0 +1 @@ +../../libs/ui/include/ui/StaticDisplayInfo.h \ No newline at end of file diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 762746c0ce..2e4f858a9d 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -36,11 +36,12 @@ #include -#include #include #include #include +#include #include +#include #include @@ -323,32 +324,26 @@ public: return result; } - status_t getDisplayInfo(const sp& display, DisplayInfo* info) override { + status_t getStaticDisplayInfo(const sp& display, + ui::StaticDisplayInfo* info) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - remote()->transact(BnSurfaceComposer::GET_DISPLAY_INFO, data, &reply); + remote()->transact(BnSurfaceComposer::GET_STATIC_DISPLAY_INFO, data, &reply); const status_t result = reply.readInt32(); if (result != NO_ERROR) return result; return reply.read(*info); } - status_t getDisplayModes(const sp& display, Vector* modes) override { + status_t getDynamicDisplayInfo(const sp& display, + ui::DynamicDisplayInfo* info) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); - remote()->transact(BnSurfaceComposer::GET_DISPLAY_MODES, data, &reply); + remote()->transact(BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO, data, &reply); const status_t result = reply.readInt32(); - if (result == NO_ERROR) { - const size_t numModes = reply.readUint32(); - modes->clear(); - modes->resize(numModes); - for (size_t i = 0; i < numModes; i++) { - memcpy(&(modes->editItemAt(i)), reply.readInplace(sizeof(ui::DisplayMode)), - sizeof(ui::DisplayMode)); - } - } - return result; + if (result != NO_ERROR) return result; + return reply.read(*info); } status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) override { @@ -365,44 +360,6 @@ public: return result; } - int getActiveDisplayModeId(const sp& display) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - remote()->transact(BnSurfaceComposer::GET_ACTIVE_DISPLAY_MODE, data, &reply); - return reply.readInt32(); - } - - status_t getDisplayColorModes(const sp& display, - Vector* outColorModes) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getDisplayColorModes failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("getDisplayColorModes failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_COLOR_MODES, data, &reply); - if (result != NO_ERROR) { - ALOGE("getDisplayColorModes failed to transact: %d", result); - return result; - } - result = static_cast(reply.readInt32()); - if (result == NO_ERROR) { - size_t numModes = reply.readUint32(); - outColorModes->clear(); - outColorModes->resize(numModes); - for (size_t i = 0; i < numModes; ++i) { - outColorModes->replaceAt(static_cast(reply.readInt32()), i); - } - } - return result; - } - status_t getDisplayNativePrimaries(const sp& display, ui::DisplayPrimaries& primaries) override { Parcel data, reply; @@ -429,26 +386,6 @@ public: return result; } - ColorMode getActiveColorMode(const sp& display) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getActiveColorMode failed to writeInterfaceToken: %d", result); - return static_cast(result); - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("getActiveColorMode failed to writeStrongBinder: %d", result); - return static_cast(result); - } - result = remote()->transact(BnSurfaceComposer::GET_ACTIVE_COLOR_MODE, data, &reply); - if (result != NO_ERROR) { - ALOGE("getActiveColorMode failed to transact: %d", result); - return static_cast(result); - } - return static_cast(reply.readInt32()); - } - status_t setActiveColorMode(const sp& display, ColorMode colorMode) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -580,28 +517,6 @@ public: return reply.readInt32(); } - status_t getHdrCapabilities(const sp& display, - HdrCapabilities* outCapabilities) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("getHdrCapabilities failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::GET_HDR_CAPABILITIES, - data, &reply); - if (result != NO_ERROR) { - ALOGE("getHdrCapabilities failed to transact: %d", result); - return result; - } - result = reply.readInt32(); - if (result == NO_ERROR) { - result = reply.read(*outCapabilities); - } - return result; - } - status_t enableVSyncInjections(bool enable) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -881,9 +796,10 @@ public: return error; } - status_t setDesiredDisplayModeSpecs(const sp& displayToken, size_t defaultMode, - bool allowGroupSwitching, float primaryRefreshRateMin, - float primaryRefreshRateMax, float appRequestRefreshRateMin, + status_t setDesiredDisplayModeSpecs(const sp& displayToken, + ui::DisplayModeId defaultMode, bool allowGroupSwitching, + float primaryRefreshRateMin, float primaryRefreshRateMax, + float appRequestRefreshRateMin, float appRequestRefreshRateMax) override { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -938,7 +854,8 @@ public: return reply.readInt32(); } - status_t getDesiredDisplayModeSpecs(const sp& displayToken, size_t* outDefaultMode, + status_t getDesiredDisplayModeSpecs(const sp& displayToken, + ui::DisplayModeId* outDefaultMode, bool* outAllowGroupSwitching, float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, @@ -966,17 +883,16 @@ public: ALOGE("getDesiredDisplayModeSpecs failed to transact: %d", result); return result; } - int32_t defaultMode; - result = reply.readInt32(&defaultMode); + + result = reply.readInt32(outDefaultMode); if (result != NO_ERROR) { ALOGE("getDesiredDisplayModeSpecs failed to read defaultMode: %d", result); return result; } - if (defaultMode < 0) { - ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, defaultMode); + if (*outDefaultMode < 0) { + ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, *outDefaultMode); return BAD_VALUE; } - *outDefaultMode = static_cast(defaultMode); result = reply.readBool(outAllowGroupSwitching); if (result != NO_ERROR) { @@ -1436,28 +1352,24 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } - case GET_DISPLAY_INFO: { + case GET_STATIC_DISPLAY_INFO: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - DisplayInfo info; + ui::StaticDisplayInfo info; const sp display = data.readStrongBinder(); - const status_t result = getDisplayInfo(display, &info); - reply->writeInt32(result); + const status_t result = getStaticDisplayInfo(display, &info); + SAFE_PARCEL(reply->writeInt32, result); if (result != NO_ERROR) return result; - return reply->write(info); + SAFE_PARCEL(reply->write, info); + return NO_ERROR; } - case GET_DISPLAY_MODES: { + case GET_DYNAMIC_DISPLAY_INFO: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - Vector modes; + ui::DynamicDisplayInfo info; const sp display = data.readStrongBinder(); - const status_t result = getDisplayModes(display, &modes); - reply->writeInt32(result); - if (result == NO_ERROR) { - reply->writeUint32(static_cast(modes.size())); - for (size_t i = 0; i < modes.size(); i++) { - memcpy(reply->writeInplace(sizeof(ui::DisplayMode)), &modes[i], - sizeof(ui::DisplayMode)); - } - } + const status_t result = getDynamicDisplayInfo(display, &info); + SAFE_PARCEL(reply->writeInt32, result); + if (result != NO_ERROR) return result; + SAFE_PARCEL(reply->write, info); return NO_ERROR; } case GET_DISPLAY_STATS: { @@ -1472,32 +1384,6 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } - case GET_ACTIVE_DISPLAY_MODE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp display = data.readStrongBinder(); - int id = getActiveDisplayModeId(display); - reply->writeInt32(id); - return NO_ERROR; - } - case GET_DISPLAY_COLOR_MODES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - Vector colorModes; - sp display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getDisplayColorModes failed to readStrongBinder: %d", result); - return result; - } - result = getDisplayColorModes(display, &colorModes); - reply->writeInt32(result); - if (result == NO_ERROR) { - reply->writeUint32(static_cast(colorModes.size())); - for (size_t i = 0; i < colorModes.size(); ++i) { - reply->writeInt32(static_cast(colorModes[i])); - } - } - return NO_ERROR; - } case GET_DISPLAY_NATIVE_PRIMARIES: { CHECK_INTERFACE(ISurfaceComposer, data, reply); ui::DisplayPrimaries primaries; @@ -1518,18 +1404,6 @@ status_t BnSurfaceComposer::onTransact( return NO_ERROR; } - case GET_ACTIVE_COLOR_MODE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getActiveColorMode failed to readStrongBinder: %d", result); - return result; - } - ColorMode colorMode = getActiveColorMode(display); - result = reply->writeInt32(static_cast(colorMode)); - return result; - } case SET_ACTIVE_COLOR_MODE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = nullptr; @@ -1639,23 +1513,6 @@ status_t BnSurfaceComposer::onTransact( setPowerMode(display, mode); return NO_ERROR; } - case GET_HDR_CAPABILITIES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getHdrCapabilities failed to readStrongBinder: %d", - result); - return result; - } - HdrCapabilities capabilities; - result = getHdrCapabilities(display, &capabilities); - reply->writeInt32(result); - if (result == NO_ERROR) { - reply->write(capabilities); - } - return NO_ERROR; - } case ENABLE_VSYNC_INJECTIONS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); bool enable = false; @@ -1862,7 +1719,7 @@ status_t BnSurfaceComposer::onTransact( case SET_DESIRED_DISPLAY_MODE_SPECS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp displayToken = data.readStrongBinder(); - int32_t defaultMode; + ui::DisplayModeId defaultMode; status_t result = data.readInt32(&defaultMode); if (result != NO_ERROR) { ALOGE("setDesiredDisplayModeSpecs: failed to read defaultMode: %d", result); @@ -1906,10 +1763,9 @@ status_t BnSurfaceComposer::onTransact( result); return result; } - result = setDesiredDisplayModeSpecs(displayToken, static_cast(defaultMode), - allowGroupSwitching, primaryRefreshRateMin, - primaryRefreshRateMax, appRequestRefreshRateMin, - appRequestRefreshRateMax); + result = setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, + primaryRefreshRateMin, primaryRefreshRateMax, + appRequestRefreshRateMin, appRequestRefreshRateMax); if (result != NO_ERROR) { ALOGE("setDesiredDisplayModeSpecs: failed to call setDesiredDisplayModeSpecs: " "%d", @@ -1922,7 +1778,7 @@ status_t BnSurfaceComposer::onTransact( case GET_DESIRED_DISPLAY_MODE_SPECS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp displayToken = data.readStrongBinder(); - size_t defaultMode; + ui::DisplayModeId defaultMode; bool allowGroupSwitching; float primaryRefreshRateMin; float primaryRefreshRateMax; @@ -1941,7 +1797,7 @@ status_t BnSurfaceComposer::onTransact( return result; } - result = reply->writeInt32(static_cast(defaultMode)); + result = reply->writeInt32(defaultMode); if (result != NO_ERROR) { ALOGE("getDesiredDisplayModeSpecs: failed to write defaultMode: %d", result); return result; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 07fc0694d6..6de3e971b2 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -34,9 +34,9 @@ #include #include +#include #include #include -#include #include #include @@ -48,7 +48,6 @@ namespace android { -using ui::ColorMode; using ui::Dataspace; namespace { @@ -361,15 +360,12 @@ status_t Surface::getHdrSupport(bool* supported) { return NAME_NOT_FOUND; } - HdrCapabilities hdrCapabilities; - status_t err = - composerService()->getHdrCapabilities(display, &hdrCapabilities); - - if (err) + ui::DynamicDisplayInfo info; + if (status_t err = composerService()->getDynamicDisplayInfo(display, &info); err != NO_ERROR) { return err; + } - *supported = !hdrCapabilities.getSupportedHdrTypes().empty(); - + *supported = !info.hdrCapabilities.getSupportedHdrTypes().empty(); return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 27fb2a8cd7..0bd2c8811b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #ifndef NO_INPUT #include @@ -1815,39 +1816,35 @@ status_t SurfaceComposerClient::getDisplayState(const sp& display, return ComposerService::getComposerService()->getDisplayState(display, state); } -status_t SurfaceComposerClient::getDisplayInfo(const sp& display, DisplayInfo* info) { - return ComposerService::getComposerService()->getDisplayInfo(display, info); +status_t SurfaceComposerClient::getStaticDisplayInfo(const sp& display, + ui::StaticDisplayInfo* info) { + return ComposerService::getComposerService()->getStaticDisplayInfo(display, info); } -status_t SurfaceComposerClient::getDisplayModes(const sp& display, - Vector* modes) { - return ComposerService::getComposerService()->getDisplayModes(display, modes); +status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp& display, + ui::DynamicDisplayInfo* info) { + return ComposerService::getComposerService()->getDynamicDisplayInfo(display, info); } status_t SurfaceComposerClient::getActiveDisplayMode(const sp& display, ui::DisplayMode* mode) { - Vector modes; - status_t result = getDisplayModes(display, &modes); + ui::DynamicDisplayInfo info; + status_t result = getDynamicDisplayInfo(display, &info); if (result != NO_ERROR) { return result; } - int activeId = getActiveDisplayModeId(display); - if (activeId < 0) { - ALOGE("No active mode found"); - return NAME_NOT_FOUND; + if (const auto activeMode = info.getActiveDisplayMode()) { + *mode = *activeMode; + return NO_ERROR; } - *mode = modes[static_cast(activeId)]; - return NO_ERROR; -} - -int SurfaceComposerClient::getActiveDisplayModeId(const sp& display) { - return ComposerService::getComposerService()->getActiveDisplayModeId(display); + ALOGE("Active display mode not found."); + return NAME_NOT_FOUND; } status_t SurfaceComposerClient::setDesiredDisplayModeSpecs( - const sp& displayToken, size_t defaultMode, bool allowGroupSwitching, + const sp& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, float appRequestRefreshRateMax) { return ComposerService::getComposerService() @@ -1856,30 +1853,24 @@ status_t SurfaceComposerClient::setDesiredDisplayModeSpecs( appRequestRefreshRateMin, appRequestRefreshRateMax); } -status_t SurfaceComposerClient::getDesiredDisplayModeSpecs( - const sp& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) { +status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp& displayToken, + ui::DisplayModeId* outDefaultMode, + bool* outAllowGroupSwitching, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { return ComposerService::getComposerService() ->getDesiredDisplayModeSpecs(displayToken, outDefaultMode, outAllowGroupSwitching, outPrimaryRefreshRateMin, outPrimaryRefreshRateMax, outAppRequestRefreshRateMin, outAppRequestRefreshRateMax); } -status_t SurfaceComposerClient::getDisplayColorModes(const sp& display, - Vector* outColorModes) { - return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes); -} - status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp& display, ui::DisplayPrimaries& outPrimaries) { return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries); } -ColorMode SurfaceComposerClient::getActiveColorMode(const sp& display) { - return ComposerService::getComposerService()->getActiveColorMode(display); -} - status_t SurfaceComposerClient::setActiveColorMode(const sp& display, ColorMode colorMode) { return ComposerService::getComposerService()->setActiveColorMode(display, colorMode); @@ -1932,12 +1923,6 @@ status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) { return ComposerService::getComposerService()->getAnimationFrameStats(outStats); } -status_t SurfaceComposerClient::getHdrCapabilities(const sp& display, - HdrCapabilities* outCapabilities) { - return ComposerService::getComposerService()->getHdrCapabilities(display, - outCapabilities); -} - status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index e842382ded..1dcfe2e804 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -30,9 +30,9 @@ #include -#include #include #include +#include #include #include diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 292838e9ae..d0ab4802e1 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -54,7 +55,6 @@ namespace android { struct client_cache_t; struct ComposerState; struct DisplayCaptureArgs; -struct DisplayInfo; struct DisplayStatInfo; struct DisplayState; struct InputWindowCommands; @@ -74,6 +74,8 @@ namespace ui { struct DisplayMode; struct DisplayState; +struct DynamicDisplayInfo; +struct StaticDisplayInfo; } // namespace ui @@ -202,26 +204,17 @@ public: virtual status_t getDisplayState(const sp& display, ui::DisplayState*) = 0; /** - * Get immutable information about given physical display. + * Gets immutable information about given physical display. */ - virtual status_t getDisplayInfo(const sp& display, DisplayInfo*) = 0; + virtual status_t getStaticDisplayInfo(const sp& display, ui::StaticDisplayInfo*) = 0; /** - * Get modes supported by given physical display. + * Gets dynamic information about given physical display. */ - virtual status_t getDisplayModes(const sp& display, Vector*) = 0; + virtual status_t getDynamicDisplayInfo(const sp& display, ui::DynamicDisplayInfo*) = 0; - /** - * Get the index into modes returned by getDisplayModes, - * corresponding to the active mode. - */ - virtual int getActiveDisplayModeId(const sp& display) = 0; - - virtual status_t getDisplayColorModes(const sp& display, - Vector* outColorModes) = 0; virtual status_t getDisplayNativePrimaries(const sp& display, ui::DisplayPrimaries& primaries) = 0; - virtual ui::ColorMode getActiveColorMode(const sp& display) = 0; virtual status_t setActiveColorMode(const sp& display, ui::ColorMode colorMode) = 0; @@ -296,13 +289,6 @@ public: */ virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0; - /* Gets the supported HDR capabilities of the given display. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getHdrCapabilities(const sp& display, - HdrCapabilities* outCapabilities) const = 0; - virtual status_t enableVSyncInjections(bool enable) = 0; virtual status_t injectVSync(nsecs_t when) = 0; @@ -397,20 +383,21 @@ public: * * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider * switching between. Only modes with a mode group and resolution matching defaultMode - * will be considered for switching. The defaultMode index corresponds to the list of modes - * returned from getDisplayModes(). - */ - virtual status_t setDesiredDisplayModeSpecs(const sp& displayToken, size_t defaultMode, - bool allowGroupSwitching, - float primaryRefreshRateMin, - float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) = 0; - - virtual status_t getDesiredDisplayModeSpecs( - const sp& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) = 0; + * will be considered for switching. The defaultMode corresponds to an ID of mode in the list + * of supported modes returned from getDynamicDisplayInfo(). + */ + virtual status_t setDesiredDisplayModeSpecs( + const sp& displayToken, ui::DisplayModeId defaultMode, + bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, + float appRequestRefreshRateMin, float appRequestRefreshRateMax) = 0; + + virtual status_t getDesiredDisplayModeSpecs(const sp& displayToken, + ui::DisplayModeId* outDefaultMode, + bool* outAllowGroupSwitching, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) = 0; /* * Gets whether brightness operations are supported on a display. * @@ -534,7 +521,7 @@ public: // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, CREATE_CONNECTION, - GET_DISPLAY_INFO, + GET_STATIC_DISPLAY_INFO, CREATE_DISPLAY_EVENT_CONNECTION, CREATE_DISPLAY, DESTROY_DISPLAY, @@ -542,8 +529,8 @@ public: SET_TRANSACTION_STATE, AUTHENTICATE_SURFACE, GET_SUPPORTED_FRAME_TIMESTAMPS, - GET_DISPLAY_MODES, - GET_ACTIVE_DISPLAY_MODE, + GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. GET_DISPLAY_STATE, CAPTURE_DISPLAY, CAPTURE_LAYERS, @@ -551,9 +538,9 @@ public: GET_ANIMATION_FRAME_STATS, SET_POWER_MODE, GET_DISPLAY_STATS, - GET_HDR_CAPABILITIES, - GET_DISPLAY_COLOR_MODES, - GET_ACTIVE_COLOR_MODE, + GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_ACTIVE_COLOR_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. SET_ACTIVE_COLOR_MODE, ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, @@ -586,6 +573,7 @@ public: ADD_TRANSACTION_TRACE_LISTENER, GET_GPU_CONTEXT_PRIORITY, GET_EXTRA_BUFFER_COUNT, + GET_DYNAMIC_DISPLAY_INFO, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index e89f3a7b44..2b72b73d96 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -108,43 +108,33 @@ public: static status_t getDisplayState(const sp& display, ui::DisplayState*); // Get immutable information about given physical display. - static status_t getDisplayInfo(const sp& display, DisplayInfo*); + static status_t getStaticDisplayInfo(const sp& display, ui::StaticDisplayInfo*); - // Get modes supported by given physical display. - static status_t getDisplayModes(const sp& display, Vector*); + // Get dynamic information about given physical display. + static status_t getDynamicDisplayInfo(const sp& display, ui::DynamicDisplayInfo*); - // Get the ID of the active DisplayMode, as getDisplayModes index. - static int getActiveDisplayModeId(const sp& display); - - // Shorthand for getDisplayModes element at getActiveDisplayModeId index. + // Shorthand for the active display mode from getDynamicDisplayInfo(). + // TODO(b/180391891): Update clients to use getDynamicDisplayInfo and remove this function. static status_t getActiveDisplayMode(const sp& display, ui::DisplayMode*); // Sets the refresh rate boundaries for the display. - static status_t setDesiredDisplayModeSpecs(const sp& displayToken, size_t defaultMode, - bool allowGroupSwitching, - float primaryRefreshRateMin, - float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax); + static status_t setDesiredDisplayModeSpecs( + const sp& displayToken, ui::DisplayModeId defaultMode, + bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, + float appRequestRefreshRateMin, float appRequestRefreshRateMax); // Gets the refresh rate boundaries for the display. static status_t getDesiredDisplayModeSpecs(const sp& displayToken, - size_t* outDefaultMode, bool* outAllowGroupSwitching, + ui::DisplayModeId* outDefaultMode, + bool* outAllowGroupSwitching, float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax); - // Gets the list of supported color modes for the given display - static status_t getDisplayColorModes(const sp& display, - Vector* outColorModes); - // Get the coordinates of the display's native color primaries static status_t getDisplayNativePrimaries(const sp& display, ui::DisplayPrimaries& outPrimaries); - // Gets the active color mode for the given display - static ui::ColorMode getActiveColorMode(const sp& display); - // Sets the active color mode for the given display static status_t setActiveColorMode(const sp& display, ui::ColorMode colorMode); @@ -583,9 +573,6 @@ public: static status_t clearAnimationFrameStats(); static status_t getAnimationFrameStats(FrameStats* outStats); - static status_t getHdrCapabilities(const sp& display, - HdrCapabilities* outCapabilities); - static void setDisplayProjection(const sp& token, ui::Rotation orientation, const Rect& layerStackRect, const Rect& displayRect); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 43909ac00d..3397198fa0 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -734,10 +735,11 @@ public: } void setPowerMode(const sp& /*display*/, int /*mode*/) override {} - status_t getDisplayInfo(const sp& /*display*/, DisplayInfo*) override { + status_t getStaticDisplayInfo(const sp& /*display*/, ui::StaticDisplayInfo*) override { return NO_ERROR; } - status_t getDisplayModes(const sp& /*display*/, Vector*) override { + status_t getDynamicDisplayInfo(const sp& /*display*/, + ui::DynamicDisplayInfo*) override { return NO_ERROR; } status_t getDisplayState(const sp& /*display*/, ui::DisplayState*) override { @@ -745,19 +747,10 @@ public: } status_t getDisplayStats(const sp& /*display*/, DisplayStatInfo* /*stats*/) override { return NO_ERROR; } - int getActiveDisplayModeId(const sp& /*display*/) override { return 0; } - status_t getDisplayColorModes(const sp& /*display*/, - Vector* /*outColorModes*/) override { - return NO_ERROR; - } status_t getDisplayNativePrimaries(const sp& /*display*/, ui::DisplayPrimaries& /*primaries*/) override { return NO_ERROR; } - ColorMode getActiveColorMode(const sp& /*display*/) - override { - return ColorMode::NATIVE; - } status_t setActiveColorMode(const sp& /*display*/, ColorMode /*colorMode*/) override { return NO_ERROR; } status_t captureDisplay(const DisplayCaptureArgs& /* captureArgs */, @@ -787,10 +780,6 @@ public: status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { return NO_ERROR; } - status_t getHdrCapabilities(const sp& /*display*/, - HdrCapabilities* /*outCapabilities*/) const override { - return NO_ERROR; - } status_t enableVSyncInjections(bool /*enable*/) override { return NO_ERROR; } @@ -843,7 +832,8 @@ public: const sp& /*listener*/) override { return NO_ERROR; } - status_t setDesiredDisplayModeSpecs(const sp& /*displayToken*/, size_t /*defaultMode*/, + status_t setDesiredDisplayModeSpecs(const sp& /*displayToken*/, + ui::DisplayModeId /*defaultMode*/, bool /*allowGroupSwitching*/, float /*primaryRefreshRateMin*/, float /*primaryRefreshRateMax*/, @@ -852,7 +842,7 @@ public: return NO_ERROR; } status_t getDesiredDisplayModeSpecs(const sp& /*displayToken*/, - size_t* /*outDefaultMode*/, + ui::DisplayModeId* /*outDefaultMode*/, bool* /*outAllowGroupSwitching*/, float* /*outPrimaryRefreshRateMin*/, float* /*outPrimaryRefreshRateMax*/, diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp index c595aa6309..6288194714 100644 --- a/libs/nativedisplay/ADisplay.cpp +++ b/libs/nativedisplay/ADisplay.cpp @@ -16,10 +16,11 @@ #include #include -#include #include +#include #include #include +#include #include #include @@ -32,6 +33,11 @@ namespace android::display::impl { * Implementation of ADisplayConfig */ struct DisplayConfigImpl { + /** + * The ID of the display configuration. + */ + size_t id; + /** * The width in pixels of the display configuration. */ @@ -139,17 +145,19 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { for (int i = 0; i < size; ++i) { const sp token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]); - DisplayInfo info; - if (const status_t status = SurfaceComposerClient::getDisplayInfo(token, &info); + ui::StaticDisplayInfo staticInfo; + if (const status_t status = SurfaceComposerClient::getStaticDisplayInfo(token, &staticInfo); status != OK) { return status; } - Vector modes; - if (const status_t status = SurfaceComposerClient::getDisplayModes(token, &modes); + ui::DynamicDisplayInfo dynamicInfo; + if (const status_t status = + SurfaceComposerClient::getDynamicDisplayInfo(token, &dynamicInfo); status != OK) { return status; } + const auto& modes = dynamicInfo.supportedDisplayModes; if (modes.empty()) { return NO_INIT; } @@ -159,9 +167,9 @@ int ADisplay_acquirePhysicalDisplays(ADisplay*** outDisplays) { for (int j = 0; j < modes.size(); ++j) { const ui::DisplayMode& mode = modes[j]; modesPerDisplay[i].emplace_back( - DisplayConfigImpl{mode.resolution.getWidth(), mode.resolution.getHeight(), - info.density, mode.refreshRate, mode.sfVsyncOffset, - mode.appVsyncOffset}); + DisplayConfigImpl{static_cast(mode.id), mode.resolution.getWidth(), + mode.resolution.getHeight(), staticInfo.density, + mode.refreshRate, mode.sfVsyncOffset, mode.appVsyncOffset}); } } @@ -257,15 +265,22 @@ int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig) { CHECK_NOT_NULL(display); sp token = getToken(display); - const int index = SurfaceComposerClient::getActiveDisplayModeId(token); - if (index < 0) { - return index; + ui::DynamicDisplayInfo info; + if (const auto status = SurfaceComposerClient::getDynamicDisplayInfo(token, &info); + status != OK) { + return status; } DisplayImpl* impl = reinterpret_cast(display); + for (size_t i = 0; i < impl->numConfigs; i++) { + auto* config = impl->configs + i; + if (config->id == info.activeDisplayModeId) { + *outConfig = reinterpret_cast(config); + return OK; + } + } - *outConfig = reinterpret_cast(impl->configs + index); - return OK; + return NAME_NOT_FOUND; } float ADisplayConfig_getDensity(ADisplayConfig* config) { diff --git a/libs/nativedisplay/include/apex/display.h b/libs/nativedisplay/include/apex/display.h index a7eaf87b9e..bd94b5523e 100644 --- a/libs/nativedisplay/include/apex/display.h +++ b/libs/nativedisplay/include/apex/display.h @@ -97,6 +97,11 @@ void ADisplay_getPreferredWideColorFormat(ADisplay* display, ADataSpace* outData * such an update is observed, then this method should be recalled to get the * new current configuration. * + * After a subsequent hotplug "connected" event the supported display configs + * may change. Then the preloaded display configs will be stale and the + * call for current config may return NAME_NOT_FOUND. In this case the client + * should release and re-acquire the display handle. + * * Returns OK on success, -errno on failure. */ int ADisplay_getCurrentConfig(ADisplay* display, ADisplayConfig** outConfig); diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 714ee3e909..f160c298b6 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -105,7 +105,8 @@ cc_library_shared { srcs: [ "DebugUtils.cpp", "DeviceProductInfo.cpp", - "DisplayInfo.cpp", + "DisplayMode.cpp", + "DynamicDisplayInfo.cpp", "Fence.cpp", "FenceTime.cpp", "FrameStats.cpp", @@ -120,6 +121,7 @@ cc_library_shared { "PixelFormat.cpp", "PublicFormat.cpp", "Size.cpp", + "StaticDisplayInfo.cpp", ], include_dirs: [ diff --git a/libs/ui/DisplayInfo.cpp b/libs/ui/DisplayInfo.cpp deleted file mode 100644 index 73a78af186..0000000000 --- a/libs/ui/DisplayInfo.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -#include - -#include - -#define RETURN_IF_ERROR(op) \ - if (const status_t status = (op); status != OK) return status; - -namespace android { - -size_t DisplayInfo::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(connectionType) + - FlattenableHelpers::getFlattenedSize(density) + - FlattenableHelpers::getFlattenedSize(secure) + - FlattenableHelpers::getFlattenedSize(deviceProductInfo); -} - -status_t DisplayInfo::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, connectionType)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, density)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, secure)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, deviceProductInfo)); - return OK; -} - -status_t DisplayInfo::unflatten(void const* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &deviceProductInfo)); - return OK; -} - -} // namespace android diff --git a/libs/ui/DisplayMode.cpp b/libs/ui/DisplayMode.cpp new file mode 100644 index 0000000000..cf05dbfb05 --- /dev/null +++ b/libs/ui/DisplayMode.cpp @@ -0,0 +1,69 @@ +/* + * 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 + +#include + +#include + +#define RETURN_IF_ERROR(op) \ + if (const status_t status = (op); status != OK) return status; + +namespace android::ui { + +size_t DisplayMode::getFlattenedSize() const { + return FlattenableHelpers::getFlattenedSize(id) + + FlattenableHelpers::getFlattenedSize(resolution) + + FlattenableHelpers::getFlattenedSize(xDpi) + + FlattenableHelpers::getFlattenedSize(yDpi) + + FlattenableHelpers::getFlattenedSize(refreshRate) + + FlattenableHelpers::getFlattenedSize(appVsyncOffset) + + FlattenableHelpers::getFlattenedSize(sfVsyncOffset) + + FlattenableHelpers::getFlattenedSize(presentationDeadline) + + FlattenableHelpers::getFlattenedSize(group); +} + +status_t DisplayMode::flatten(void* buffer, size_t size) const { + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, id)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, resolution)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, xDpi)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, yDpi)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, refreshRate)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, appVsyncOffset)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, sfVsyncOffset)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, presentationDeadline)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, group)); + return OK; +} + +status_t DisplayMode::unflatten(const void* buffer, size_t size) { + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &id)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &resolution)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &xDpi)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &yDpi)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &refreshRate)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &appVsyncOffset)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &sfVsyncOffset)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &presentationDeadline)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &group)); + return OK; +} + +} // namespace android::ui diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp new file mode 100644 index 0000000000..11acdae921 --- /dev/null +++ b/libs/ui/DynamicDisplayInfo.cpp @@ -0,0 +1,66 @@ +/* + * 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 + +#include + +#include + +#define RETURN_IF_ERROR(op) \ + if (const status_t status = (op); status != OK) return status; + +namespace android::ui { + +std::optional DynamicDisplayInfo::getActiveDisplayMode() const { + for (const auto& currMode : supportedDisplayModes) { + if (currMode.id == activeDisplayModeId) { + return currMode; + } + } + return {}; +} + +size_t DynamicDisplayInfo::getFlattenedSize() const { + return FlattenableHelpers::getFlattenedSize(supportedDisplayModes) + + FlattenableHelpers::getFlattenedSize(activeDisplayModeId) + + FlattenableHelpers::getFlattenedSize(supportedColorModes) + + FlattenableHelpers::getFlattenedSize(activeColorMode) + + FlattenableHelpers::getFlattenedSize(hdrCapabilities); +} + +status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const { + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedDisplayModes)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeDisplayModeId)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedColorModes)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeColorMode)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities)); + return OK; +} + +status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) { + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedDisplayModes)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeDisplayModeId)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedColorModes)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeColorMode)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities)); + return OK; +} + +} // namespace android::ui diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp index a5b3e89314..aec2fac780 100644 --- a/libs/ui/HdrCapabilities.cpp +++ b/libs/ui/HdrCapabilities.cpp @@ -23,10 +23,6 @@ namespace android { #pragma clang diagnostic ignored "-Wundefined-reinterpret-cast" #endif -HdrCapabilities::~HdrCapabilities() = default; -HdrCapabilities::HdrCapabilities(HdrCapabilities&& other) noexcept = default; -HdrCapabilities& HdrCapabilities::operator=(HdrCapabilities&& other) noexcept = default; - size_t HdrCapabilities::getFlattenedSize() const { return sizeof(mMaxLuminance) + sizeof(mMaxAverageLuminance) + diff --git a/libs/ui/StaticDisplayInfo.cpp b/libs/ui/StaticDisplayInfo.cpp new file mode 100644 index 0000000000..b66b281394 --- /dev/null +++ b/libs/ui/StaticDisplayInfo.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +#define RETURN_IF_ERROR(op) \ + if (const status_t status = (op); status != OK) return status; + +namespace android::ui { + +size_t StaticDisplayInfo::getFlattenedSize() const { + return FlattenableHelpers::getFlattenedSize(connectionType) + + FlattenableHelpers::getFlattenedSize(density) + + FlattenableHelpers::getFlattenedSize(secure) + + FlattenableHelpers::getFlattenedSize(deviceProductInfo); +} + +status_t StaticDisplayInfo::flatten(void* buffer, size_t size) const { + if (size < getFlattenedSize()) { + return NO_MEMORY; + } + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, connectionType)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, density)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, secure)); + RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, deviceProductInfo)); + return OK; +} + +status_t StaticDisplayInfo::unflatten(void const* buffer, size_t size) { + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure)); + RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &deviceProductInfo)); + return OK; +} + +} // namespace android::ui diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h deleted file mode 100644 index 03e0a3886e..0000000000 --- a/libs/ui/include/ui/DisplayInfo.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include -#include - -namespace android { - -enum class DisplayConnectionType { Internal, External }; - -// Immutable information about physical display. -struct DisplayInfo : LightFlattenable { - DisplayConnectionType connectionType = DisplayConnectionType::Internal; - float density = 0.f; - bool secure = false; - std::optional deviceProductInfo; - - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(void const* buffer, size_t size); -}; - -} // namespace android diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h index 145d7efd19..56f68e7bb2 100644 --- a/libs/ui/include/ui/DisplayMode.h +++ b/libs/ui/include/ui/DisplayMode.h @@ -16,15 +16,21 @@ #pragma once +#include #include #include +#include #include namespace android::ui { +// This value is going to be serialized over binder so we prefer a fixed width type. +using DisplayModeId = int32_t; + // Mode supported by physical display. -struct DisplayMode { +struct DisplayMode : LightFlattenable { + DisplayModeId id; ui::Size resolution; float xDpi = 0; float yDpi = 0; @@ -33,9 +39,12 @@ struct DisplayMode { nsecs_t appVsyncOffset = 0; nsecs_t sfVsyncOffset = 0; nsecs_t presentationDeadline = 0; - int group = -1; -}; + int32_t group = -1; -static_assert(std::is_trivially_copyable_v); + bool isFixedSize() const { return false; } + size_t getFlattenedSize() const; + status_t flatten(void* buffer, size_t size) const; + status_t unflatten(const void* buffer, size_t size); +}; } // namespace android::ui diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h new file mode 100644 index 0000000000..6c349b749d --- /dev/null +++ b/libs/ui/include/ui/DynamicDisplayInfo.h @@ -0,0 +1,52 @@ +/* + * 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 "DisplayMode.h" + +#include +#include +#include + +#include +#include +#include + +namespace android::ui { + +// Information about a physical display which may change on hotplug reconnect. +struct DynamicDisplayInfo : LightFlattenable { + std::vector supportedDisplayModes; + + // This struct is going to be serialized over binder, so + // we can't use size_t because it may have different width + // in the client process. + int32_t activeDisplayModeId; + + std::vector supportedColorModes; + ui::ColorMode activeColorMode; + HdrCapabilities hdrCapabilities; + + std::optional getActiveDisplayMode() const; + + bool isFixedSize() const { return false; } + size_t getFlattenedSize() const; + status_t flatten(void* buffer, size_t size) const; + status_t unflatten(const void* buffer, size_t size); +}; + +} // namespace android::ui diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h index 65ac26cf7e..813addeca6 100644 --- a/libs/ui/include/ui/HdrCapabilities.h +++ b/libs/ui/include/ui/HdrCapabilities.h @@ -36,18 +36,12 @@ public: mMaxAverageLuminance(maxAverageLuminance), mMinLuminance(minLuminance) {} - // Make this move-constructable and move-assignable - HdrCapabilities(HdrCapabilities&& other) noexcept; - HdrCapabilities& operator=(HdrCapabilities&& other) noexcept; - HdrCapabilities() : mSupportedHdrTypes(), mMaxLuminance(-1.0f), mMaxAverageLuminance(-1.0f), mMinLuminance(-1.0f) {} - ~HdrCapabilities(); - const std::vector& getSupportedHdrTypes() const { return mSupportedHdrTypes; } diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h new file mode 100644 index 0000000000..e86ca29a2a --- /dev/null +++ b/libs/ui/include/ui/StaticDisplayInfo.h @@ -0,0 +1,41 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +namespace android::ui { + +enum class DisplayConnectionType { Internal, External }; + +// Immutable information about physical display. +struct StaticDisplayInfo : LightFlattenable { + DisplayConnectionType connectionType = DisplayConnectionType::Internal; + float density = 0.f; + bool secure = false; + std::optional deviceProductInfo; + + bool isFixedSize() const { return false; } + size_t getFlattenedSize() const; + status_t flatten(void* buffer, size_t size) const; + status_t unflatten(void const* buffer, size_t size); +}; + +} // namespace android::ui diff --git a/libs/ui/include_vndk/ui/DisplayInfo.h b/libs/ui/include_vndk/ui/DisplayInfo.h deleted file mode 120000 index 75f14cf66d..0000000000 --- a/libs/ui/include_vndk/ui/DisplayInfo.h +++ /dev/null @@ -1 +0,0 @@ -../../include/ui/DisplayInfo.h \ No newline at end of file diff --git a/libs/ui/include_vndk/ui/StaticDisplayInfo.h b/libs/ui/include_vndk/ui/StaticDisplayInfo.h new file mode 120000 index 0000000000..541a7a37b9 --- /dev/null +++ b/libs/ui/include_vndk/ui/StaticDisplayInfo.h @@ -0,0 +1 @@ +../../include/ui/StaticDisplayInfo.h \ No newline at end of file diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h index 95ba9f0429..633668e1c2 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h @@ -21,9 +21,9 @@ #include #include -#include #include #include +#include #include "DisplayHardware/DisplayIdentification.h" #include "DisplayHardware/PowerAdvisor.h" @@ -39,7 +39,7 @@ class CompositionEngine; struct DisplayCreationArgs { struct Physical { DisplayId id; - DisplayConnectionType type; + ui::DisplayConnectionType type; }; // Required for physical displays. Gives the HWC display id for the existing diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp index 0b0b8d5e9c..a605fe1dc3 100644 --- a/services/surfaceflinger/CompositionEngine/src/Display.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp @@ -55,7 +55,8 @@ void Display::setConfiguration(const compositionengine::DisplayCreationArgs& arg editState().isSecure = args.isSecure; editState().displaySpace.bounds = Rect(args.pixels); setLayerStackFilter(args.layerStackId, - args.physical && args.physical->type == DisplayConnectionType::Internal); + args.physical && + args.physical->type == ui::DisplayConnectionType::Internal); setName(args.name); mGpuVirtualDisplayIdGenerator = args.gpuVirtualDisplayIdGenerator; diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp index 348ec398ae..8a83639ce5 100644 --- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp @@ -35,8 +35,8 @@ #include #include #include -#include #include +#include #include "MockHWC2.h" #include "MockHWComposer.h" @@ -169,7 +169,7 @@ struct DisplayTestCommon : public testing::Test { DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() { return DisplayCreationArgsBuilder() - .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) .setIsSecure(true) @@ -265,7 +265,7 @@ TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) { mDisplay->setConfiguration( DisplayCreationArgsBuilder() .setUseHwcVirtualDisplays(true) - .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) .setIsSecure(true) @@ -286,7 +286,7 @@ TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) { mDisplay->setConfiguration( DisplayCreationArgsBuilder() .setUseHwcVirtualDisplays(true) - .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::External}) + .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::External}) .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH)) .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) .setIsSecure(false) @@ -1018,7 +1018,7 @@ struct DisplayFunctionalTest : public testing::Test { std::shared_ptr mDisplay = impl::createDisplayTemplated< Display>(mCompositionEngine, DisplayCreationArgsBuilder() - .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setPixelFormat(static_cast(PIXEL_FORMAT_RGBA_8888)) .setIsSecure(true) diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index ab003852de..bac894a6dc 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -91,7 +91,7 @@ public: MOCK_CONST_METHOD1(getColorModes, std::vector(PhysicalDisplayId)); MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent)); MOCK_CONST_METHOD0(isUsingVrComposer, bool()); - MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId)); + MOCK_CONST_METHOD1(getDisplayConnectionType, ui::DisplayConnectionType(PhysicalDisplayId)); MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId)); MOCK_CONST_METHOD2(getDisplayVsyncPeriod, status_t(PhysicalDisplayId, nsecs_t*)); MOCK_METHOD4(setActiveModeWithConstraints, diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index c751f22c97..36c4c4d5ba 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -173,7 +173,7 @@ const DisplayModes& DisplayDevice::getSupportedModes() const { DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const { const auto id = modeId.value(); - if (id < mSupportedModes.size()) { + if (static_cast(id) < mSupportedModes.size()) { return mSupportedModes[id]; } return nullptr; @@ -254,7 +254,7 @@ ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() { std::string DisplayDevice::getDebugName() const { const char* type = "virtual"; if (mConnectionType) { - type = *mConnectionType == DisplayConnectionType::Internal ? "internal" : "external"; + type = *mConnectionType == ui::DisplayConnectionType::Internal ? "internal" : "external"; } return base::StringPrintf("DisplayDevice{%s, %s%s, \"%s\"}", to_string(getId()).c_str(), type, diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index b4db933e19..a94bfa269d 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -28,11 +28,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -74,7 +74,7 @@ public: return mCompositionDisplay; } - std::optional getConnectionType() const { return mConnectionType; } + std::optional getConnectionType() const { return mConnectionType; } bool isVirtual() const { return !mConnectionType; } bool isPrimary() const { return mIsPrimary; } @@ -195,7 +195,7 @@ private: HWComposer& mHwComposer; const wp mDisplayToken; const int32_t mSequenceId; - const std::optional mConnectionType; + const std::optional mConnectionType; const std::shared_ptr mCompositionDisplay; @@ -222,7 +222,7 @@ private: struct DisplayDeviceState { struct Physical { PhysicalDisplayId id; - DisplayConnectionType type; + ui::DisplayConnectionType type; hardware::graphics::composer::hal::HWDisplayId hwcDisplayId; std::optional deviceProductInfo; DisplayModes supportedModes; @@ -263,7 +263,7 @@ struct DisplayDeviceCreationArgs { const std::shared_ptr compositionDisplay; int32_t sequenceId{0}; - std::optional connectionType; + std::optional connectionType; bool isSecure{false}; sp nativeWindow; sp displaySurface; diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h index 1f0f3c3c33..853c05b244 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayMode.h +++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -36,7 +37,7 @@ namespace hal = android::hardware::graphics::composer::hal; class DisplayMode; using DisplayModePtr = std::shared_ptr; using DisplayModes = std::vector; -using DisplayModeId = StrongTyping; +using DisplayModeId = StrongTyping; class DisplayMode { public: @@ -139,7 +140,7 @@ private: }; inline std::string to_string(const DisplayMode& mode) { - return base::StringPrintf("{id=%zu, hwcId=%d, width=%d, height=%d, refreshRate=%s, " + return base::StringPrintf("{id=%d, hwcId=%d, width=%d, height=%d, refreshRate=%s, " "dpiX=%.2f, dpiY=%.2f, group=%d}", mode.getId().value(), mode.getHwcId(), mode.getWidth(), mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(), diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 71a3276d1b..d04b5f7316 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -264,7 +264,7 @@ Error Display::getRequests(HWC2::DisplayRequest* outDisplayRequests, return Error::NONE; } -Error Display::getConnectionType(android::DisplayConnectionType* outType) const { +Error Display::getConnectionType(ui::DisplayConnectionType* outType) const { if (mType != DisplayType::PHYSICAL) return Error::BAD_DISPLAY; using ConnectionType = Hwc2::IComposerClient::DisplayConnectionType; @@ -274,9 +274,8 @@ Error Display::getConnectionType(android::DisplayConnectionType* outType) const return error; } - *outType = connectionType == ConnectionType::INTERNAL - ? android::DisplayConnectionType::Internal - : android::DisplayConnectionType::External; + *outType = connectionType == ConnectionType::INTERNAL ? ui::DisplayConnectionType::Internal + : ui::DisplayConnectionType::External; return Error::NONE; } diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 4c7f28412d..e7bf286d08 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -18,9 +18,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -104,7 +104,7 @@ public: hal::DisplayRequest* outDisplayRequests, std::unordered_map* outLayerRequests) = 0; [[clang::warn_unused_result]] virtual hal::Error getConnectionType( - android::DisplayConnectionType*) const = 0; + ui::DisplayConnectionType*) const = 0; [[clang::warn_unused_result]] virtual hal::Error supportsDoze(bool* outSupport) const = 0; [[clang::warn_unused_result]] virtual hal::Error getHdrCapabilities( android::HdrCapabilities* outCapabilities) const = 0; @@ -175,7 +175,7 @@ public: hal::Error getRequests( hal::DisplayRequest* outDisplayRequests, std::unordered_map* outLayerRequests) override; - hal::Error getConnectionType(android::DisplayConnectionType*) const override; + hal::Error getConnectionType(ui::DisplayConnectionType*) const override; hal::Error supportsDoze(bool* outSupport) const override; hal::Error getHdrCapabilities(android::HdrCapabilities* outCapabilities) const override; hal::Error getDisplayedContentSamplingAttributes(hal::PixelFormat* outFormat, diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index b9a8e4be37..ccfaa76374 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -369,16 +369,16 @@ std::optional HWComposer::getActiveMode(PhysicalDisplayId displ // Composer 2.4 -DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const { - RETURN_IF_INVALID_DISPLAY(displayId, DisplayConnectionType::Internal); +ui::DisplayConnectionType HWComposer::getDisplayConnectionType(PhysicalDisplayId displayId) const { + RETURN_IF_INVALID_DISPLAY(displayId, ui::DisplayConnectionType::Internal); const auto& hwcDisplay = mDisplayData.at(displayId).hwcDisplay; - DisplayConnectionType type; + ui::DisplayConnectionType type; const auto error = hwcDisplay->getConnectionType(&type); const auto FALLBACK_TYPE = hwcDisplay->getId() == mInternalHwcDisplayId - ? DisplayConnectionType::Internal - : DisplayConnectionType::External; + ? ui::DisplayConnectionType::Internal + : ui::DisplayConnectionType::External; RETURN_IF_HWC_ERROR(error, displayId, FALLBACK_TYPE); return type; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index f9c8e2efef..cf6bc68897 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -204,7 +204,7 @@ public: ui::RenderIntent) = 0; // Composer 2.4 - virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0; + virtual ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0; virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0; virtual status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId, nsecs_t* outVsyncPeriod) const = 0; @@ -335,7 +335,7 @@ public: status_t setActiveColorMode(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent) override; // Composer 2.4 - DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override; + ui::DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override; bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override; status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId, nsecs_t* outVsyncPeriod) const override; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp index a03f79384e..de11c16f64 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp @@ -64,7 +64,7 @@ using AllRefreshRatesMapType = RefreshRateConfigs::AllRefreshRatesMapType; using RefreshRate = RefreshRateConfigs::RefreshRate; std::string RefreshRate::toString() const { - return base::StringPrintf("{id=%zu, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", + return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}", getModeId().value(), mode->getHwcId(), getFps().getValue(), mode->getWidth(), mode->getHeight(), getModeGroup()); } @@ -89,7 +89,7 @@ std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) { } std::string RefreshRateConfigs::Policy::toString() const { - return base::StringPrintf("default mode ID: %zu, allowGroupSwitching = %d" + return base::StringPrintf("default mode ID: %d, allowGroupSwitching = %d" ", primary range: %s, app request range: %s", defaultMode.value(), allowGroupSwitching, primaryRange.toString().c_str(), appRequestRange.toString().c_str()); @@ -724,7 +724,7 @@ void RefreshRateConfigs::getSortedRefreshRateListLocked( outRefreshRates->reserve(mRefreshRates.size()); for (const auto& [type, refreshRate] : mRefreshRates) { if (shouldAddRefreshRate(*refreshRate)) { - ALOGV("getSortedRefreshRateListLocked: mode %zu added to list policy", + ALOGV("getSortedRefreshRateListLocked: mode %d added to list policy", refreshRate->modeId.value()); outRefreshRates->push_back(refreshRate.get()); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 7fada820e4..ecf535835a 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -68,12 +68,13 @@ #include #include #include -#include #include #include #include +#include #include #include +#include #include #include #include @@ -854,7 +855,8 @@ status_t SurfaceFlinger::getDisplayState(const sp& displayToken, ui::Di return NO_ERROR; } -status_t SurfaceFlinger::getDisplayInfo(const sp& displayToken, DisplayInfo* info) { +status_t SurfaceFlinger::getStaticDisplayInfo(const sp& displayToken, + ui::StaticDisplayInfo* info) { if (!displayToken || !info) { return BAD_VALUE; } @@ -875,7 +877,7 @@ status_t SurfaceFlinger::getDisplayInfo(const sp& displayToken, Display if (mEmulatedDisplayDensity) { info->density = mEmulatedDisplayDensity; } else { - info->density = info->connectionType == DisplayConnectionType::Internal + info->density = info->connectionType == ui::DisplayConnectionType::Internal ? mInternalDisplayDensity : FALLBACK_DENSITY; } @@ -887,9 +889,9 @@ status_t SurfaceFlinger::getDisplayInfo(const sp& displayToken, Display return NO_ERROR; } -status_t SurfaceFlinger::getDisplayModes(const sp& displayToken, - Vector* modes) { - if (!displayToken || !modes) { +status_t SurfaceFlinger::getDynamicDisplayInfo(const sp& displayToken, + ui::DynamicDisplayInfo* info) { + if (!displayToken || !info) { return BAD_VALUE; } @@ -900,16 +902,25 @@ status_t SurfaceFlinger::getDisplayModes(const sp& displayToken, return NAME_NOT_FOUND; } - modes->clear(); + info->activeDisplayModeId = static_cast(display->getActiveMode()->getId().value()); + if (display->isPrimary()) { + if (const auto mode = getDesiredActiveMode()) { + info->activeDisplayModeId = static_cast(mode->modeId.value()); + } + } - for (const auto& supportedMode : display->getSupportedModes()) { - ui::DisplayMode mode; + const auto& supportedModes = display->getSupportedModes(); + info->supportedDisplayModes.clear(); + info->supportedDisplayModes.reserve(supportedModes.size()); + for (const auto& mode : supportedModes) { + ui::DisplayMode outMode; + outMode.id = static_cast(mode->getId().value()); - auto width = supportedMode->getWidth(); - auto height = supportedMode->getHeight(); + auto width = mode->getWidth(); + auto height = mode->getHeight(); - auto xDpi = supportedMode->getDpiX(); - auto yDpi = supportedMode->getDpiY(); + auto xDpi = mode->getDpiX(); + auto yDpi = mode->getDpiY(); if (display->isPrimary() && (internalDisplayOrientation == ui::ROTATION_90 || @@ -918,24 +929,24 @@ status_t SurfaceFlinger::getDisplayModes(const sp& displayToken, std::swap(xDpi, yDpi); } - mode.resolution = ui::Size(width, height); + outMode.resolution = ui::Size(width, height); if (mEmulatedDisplayDensity) { - mode.xDpi = mEmulatedDisplayDensity; - mode.yDpi = mEmulatedDisplayDensity; + outMode.xDpi = mEmulatedDisplayDensity; + outMode.yDpi = mEmulatedDisplayDensity; } else { - mode.xDpi = xDpi; - mode.yDpi = yDpi; + outMode.xDpi = xDpi; + outMode.yDpi = yDpi; } - const nsecs_t period = supportedMode->getVsyncPeriod(); - mode.refreshRate = Fps::fromPeriodNsecs(period).getValue(); + const nsecs_t period = mode->getVsyncPeriod(); + outMode.refreshRate = Fps::fromPeriodNsecs(period).getValue(); const auto vsyncConfigSet = - mVsyncConfiguration->getConfigsForRefreshRate(Fps(mode.refreshRate)); - mode.appVsyncOffset = vsyncConfigSet.late.appOffset; - mode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; - mode.group = supportedMode->getGroup(); + mVsyncConfiguration->getConfigsForRefreshRate(Fps(outMode.refreshRate)); + outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; + outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; + outMode.group = mode->getGroup(); // This is how far in advance a buffer must be queued for // presentation at a given time. If you want a buffer to appear @@ -949,11 +960,15 @@ status_t SurfaceFlinger::getDisplayModes(const sp& displayToken, // // We add an additional 1ms to allow for processing time and // differences between the ideal and actual refresh rate. - mode.presentationDeadline = period - mode.sfVsyncOffset + 1000000; + outMode.presentationDeadline = period - outMode.sfVsyncOffset + 1000000; - modes->push_back(mode); + info->supportedDisplayModes.push_back(outMode); } + info->activeColorMode = display->getCompositionDisplay()->getState().colorMode; + info->supportedColorModes = getDisplayColorModes(display->getPhysicalId()); + + info->hdrCapabilities = display->getHdrCapabilities(); return NO_ERROR; } @@ -966,31 +981,6 @@ status_t SurfaceFlinger::getDisplayStats(const sp&, DisplayStatInfo* st return NO_ERROR; } -int SurfaceFlinger::getActiveDisplayModeId(const sp& displayToken) { - int activeMode; - bool isPrimary; - - { - Mutex::Autolock lock(mStateLock); - - if (const auto display = getDisplayDeviceLocked(displayToken)) { - activeMode = display->getActiveMode()->getId().value(); - isPrimary = display->isPrimary(); - } else { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return NAME_NOT_FOUND; - } - } - - if (isPrimary) { - if (const auto mode = getDesiredActiveMode()) { - return mode->modeId.value(); - } - } - - return activeMode; -} - void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) { ATRACE_CALL(); auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId); @@ -1082,7 +1072,7 @@ void SurfaceFlinger::setActiveModeInternal() { const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId); if (!upcomingMode) { - ALOGW("Upcoming active mode is no longer supported. Mode ID = %zu", + ALOGW("Upcoming active mode is no longer supported. Mode ID = %d", mUpcomingActiveMode.modeId.value()); // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may // have been already updated with the upcoming active mode. @@ -1142,13 +1132,13 @@ void SurfaceFlinger::performSetActiveMode() { const auto display = getDefaultDisplayDeviceLocked(); const auto desiredMode = display->getMode(desiredActiveMode->modeId); if (!desiredMode) { - ALOGW("Desired display mode is no longer supported. Mode ID = %zu", + ALOGW("Desired display mode is no longer supported. Mode ID = %d", desiredActiveMode->modeId.value()); clearDesiredActiveModeState(); return; } const auto refreshRate = desiredMode->getFps(); - ALOGV("%s changing active mode to %zu(%s)", __FUNCTION__, desiredMode->getId().value(), + ALOGV("%s changing active mode to %d(%s)", __FUNCTION__, desiredMode->getId().value(), to_string(refreshRate).c_str()); if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) { @@ -1190,39 +1180,20 @@ void SurfaceFlinger::performSetActiveMode() { mSetActiveModePending = true; } -status_t SurfaceFlinger::getDisplayColorModes(const sp& displayToken, - Vector* outColorModes) { - if (!displayToken || !outColorModes) { - return BAD_VALUE; - } - - std::vector modes; - bool isInternalDisplay = false; - { - ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - return NAME_NOT_FOUND; - } - - modes = getHwComposer().getColorModes(*displayId); - isInternalDisplay = displayId == getInternalDisplayIdLocked(); - } - outColorModes->clear(); +std::vector SurfaceFlinger::getDisplayColorModes(PhysicalDisplayId displayId) { + auto modes = getHwComposer().getColorModes(displayId); + bool isInternalDisplay = displayId == getInternalDisplayIdLocked(); // If it's built-in display and the configuration claims it's not wide color capable, // filter out all wide color modes. The typical reason why this happens is that the // hardware is not good enough to support GPU composition of wide color, and thus the // OEMs choose to disable this capability. if (isInternalDisplay && !hasWideColorDisplay) { - std::remove_copy_if(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes), - isWideColorMode); - } else { - std::copy(modes.cbegin(), modes.cend(), std::back_inserter(*outColorModes)); + const auto newEnd = std::remove_if(modes.begin(), modes.end(), isWideColorMode); + modes.erase(newEnd, modes.end()); } - return NO_ERROR; + return modes; } status_t SurfaceFlinger::getDisplayNativePrimaries(const sp& displayToken, @@ -1240,19 +1211,14 @@ status_t SurfaceFlinger::getDisplayNativePrimaries(const sp& displayTok return NO_ERROR; } -ColorMode SurfaceFlinger::getActiveColorMode(const sp& displayToken) { - Mutex::Autolock lock(mStateLock); - - if (const auto display = getDisplayDeviceLocked(displayToken)) { - return display->getCompositionDisplay()->getState().colorMode; - } - return static_cast(BAD_VALUE); -} - status_t SurfaceFlinger::setActiveColorMode(const sp& displayToken, ColorMode mode) { schedule([=]() MAIN_THREAD { - Vector modes; - getDisplayColorModes(displayToken, &modes); + const auto displayId = getPhysicalDisplayIdLocked(displayToken); + if (!displayId) { + ALOGE("Invalid display token %p", displayToken.get()); + return; + } + const auto modes = getDisplayColorModes(*displayId); bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes); if (mode < ColorMode::NATIVE || !exists) { ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p", @@ -1349,28 +1315,6 @@ status_t SurfaceFlinger::getAnimationFrameStats(FrameStats* outStats) const { return NO_ERROR; } -status_t SurfaceFlinger::getHdrCapabilities(const sp& displayToken, - HdrCapabilities* outCapabilities) const { - Mutex::Autolock lock(mStateLock); - - const auto display = getDisplayDeviceLocked(displayToken); - if (!display) { - ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get()); - return NAME_NOT_FOUND; - } - - // At this point the DisplayDevice should already be set up, - // meaning the luminance information is already queried from - // hardware composer and stored properly. - const HdrCapabilities& capabilities = display->getHdrCapabilities(); - *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(), - capabilities.getDesiredMaxLuminance(), - capabilities.getDesiredMaxAverageLuminance(), - capabilities.getDesiredMinLuminance()); - - return NO_ERROR; -} - status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp& displayToken, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, @@ -1640,7 +1584,7 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate, // Don't do any updating if the current fps is the same as the new one. if (!isDisplayModeAllowed(refreshRate.getModeId())) { - ALOGV("Skipping mode %zu as it is not part of allowed modes", + ALOGV("Skipping mode %d as it is not part of allowed modes", refreshRate.getModeId().value()); return; } @@ -2360,7 +2304,7 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) { DisplayModes SurfaceFlinger::loadSupportedDisplayModes(PhysicalDisplayId displayId) const { const auto hwcModes = getHwComposer().getModes(displayId); DisplayModes modes; - size_t nextModeId = 0; + int32_t nextModeId = 0; for (const auto& hwcMode : hwcModes) { modes.push_back(DisplayMode::Builder(hwcMode.hwcId) .setId(DisplayModeId{nextModeId++}) @@ -5013,7 +4957,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_PHYSICAL_DISPLAY_TOKEN: case GET_DISPLAY_COLOR_MODES: case GET_DISPLAY_NATIVE_PRIMARIES: - case GET_DISPLAY_INFO: + case GET_STATIC_DISPLAY_INFO: + case GET_DYNAMIC_DISPLAY_INFO: case GET_DISPLAY_MODES: case GET_DISPLAY_STATE: case GET_DISPLAY_STATS: @@ -6141,27 +6086,25 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal( ? mRefreshRateConfigs->getRefreshRateFromModeId(*modeId) // NOTE: Choose the default mode ID, if Scheduler doesn't have one in mind. : mRefreshRateConfigs->getRefreshRateFromModeId(currentPolicy.defaultMode); - ALOGV("trying to switch to Scheduler preferred mode %zu (%s)", + ALOGV("trying to switch to Scheduler preferred mode %d (%s)", preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str()); if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) { - ALOGV("switching to Scheduler preferred display mode %zu", + ALOGV("switching to Scheduler preferred display mode %d", preferredRefreshRate.getModeId().value()); setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed}); } else { - LOG_ALWAYS_FATAL("Desired display mode not allowed: %zu", + LOG_ALWAYS_FATAL("Desired display mode not allowed: %d", preferredRefreshRate.getModeId().value()); } return NO_ERROR; } -status_t SurfaceFlinger::setDesiredDisplayModeSpecs(const sp& displayToken, - size_t defaultMode, bool allowGroupSwitching, - float primaryRefreshRateMin, - float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) { +status_t SurfaceFlinger::setDesiredDisplayModeSpecs( + const sp& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching, + float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { ATRACE_CALL(); if (!displayToken) { @@ -6192,10 +6135,13 @@ status_t SurfaceFlinger::setDesiredDisplayModeSpecs(const sp& displayTo return future.get(); } -status_t SurfaceFlinger::getDesiredDisplayModeSpecs( - const sp& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) { +status_t SurfaceFlinger::getDesiredDisplayModeSpecs(const sp& displayToken, + ui::DisplayModeId* outDefaultMode, + bool* outAllowGroupSwitching, + float* outPrimaryRefreshRateMin, + float* outPrimaryRefreshRateMax, + float* outAppRequestRefreshRateMin, + float* outAppRequestRefreshRateMax) { ATRACE_CALL(); if (!displayToken || !outDefaultMode || !outPrimaryRefreshRateMin || diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a62d0b9a95..21cd2a5682 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -552,14 +552,14 @@ private: const sp& captureListener) override; status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats) override; - status_t getDisplayState(const sp& displayToken, ui::DisplayState*) override; - status_t getDisplayInfo(const sp& displayToken, DisplayInfo*) override; - status_t getDisplayModes(const sp& displayToken, Vector*) override; - int getActiveDisplayModeId(const sp& displayToken) override; - status_t getDisplayColorModes(const sp& displayToken, Vector*) override; + status_t getDisplayState(const sp& displayToken, ui::DisplayState*) + EXCLUDES(mStateLock) override; + status_t getStaticDisplayInfo(const sp& displayToken, ui::StaticDisplayInfo*) + EXCLUDES(mStateLock) override; + status_t getDynamicDisplayInfo(const sp& displayToken, ui::DynamicDisplayInfo*) + EXCLUDES(mStateLock) override; status_t getDisplayNativePrimaries(const sp& displayToken, ui::DisplayPrimaries&) override; - ui::ColorMode getActiveColorMode(const sp& displayToken) override; status_t setActiveColorMode(const sp& displayToken, ui::ColorMode colorMode) override; status_t getAutoLowLatencyModeSupport(const sp& displayToken, bool* outSupported) const override; @@ -570,8 +570,6 @@ private: void setPowerMode(const sp& displayToken, int mode) override; status_t clearAnimationFrameStats() override; status_t getAnimationFrameStats(FrameStats* outStats) const override; - status_t getHdrCapabilities(const sp& displayToken, - HdrCapabilities* outCapabilities) const override; status_t enableVSyncInjections(bool enable) override; status_t injectVSync(nsecs_t when) override; status_t getLayerDebugInfo(std::vector* outLayers) override; @@ -594,11 +592,13 @@ private: status_t addRegionSamplingListener(const Rect& samplingArea, const sp& stopLayerHandle, const sp& listener) override; status_t removeRegionSamplingListener(const sp& listener) override; - status_t setDesiredDisplayModeSpecs(const sp& displayToken, size_t displayModeId, - bool allowGroupSwitching, float primaryRefreshRateMin, - float primaryRefreshRateMax, float appRequestRefreshRateMin, + status_t setDesiredDisplayModeSpecs(const sp& displayToken, + ui::DisplayModeId displayModeId, bool allowGroupSwitching, + float primaryRefreshRateMin, float primaryRefreshRateMax, + float appRequestRefreshRateMin, float appRequestRefreshRateMax) override; - status_t getDesiredDisplayModeSpecs(const sp& displayToken, size_t* outDefaultMode, + status_t getDesiredDisplayModeSpecs(const sp& displayToken, + ui::DisplayModeId* outDefaultMode, bool* outAllowGroupSwitching, float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, @@ -1054,6 +1054,9 @@ private: return std::nullopt; } + std::vector getDisplayColorModes(PhysicalDisplayId displayId) + REQUIRES(mStateLock); + static int calculateExtraBufferCount(Fps maxSupportedRefreshRate, std::chrono::nanoseconds presentLatency); diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 53e37d874e..6246321fab 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include "utils/ScreenshotUtils.h" @@ -188,19 +189,15 @@ TEST_F(CredentialsTest, AllowedGetterMethodsTest) { ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode)); Vector modes; - ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes)); - - ASSERT_TRUE(SurfaceComposerClient::getActiveDisplayModeId(display) >= 0); - - ASSERT_NE(static_cast(BAD_VALUE), - SurfaceComposerClient::getActiveColorMode(display)); + ui::DynamicDisplayInfo info; + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info)); } -TEST_F(CredentialsTest, GetDisplayColorModesTest) { +TEST_F(CredentialsTest, GetDynamicDisplayInfoTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { - Vector outColorModes; - return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes); + ui::DynamicDisplayInfo info; + return SurfaceComposerClient::getDynamicDisplayInfo(display, &info); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } @@ -216,7 +213,7 @@ TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) { TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); - size_t defaultMode; + ui::DisplayModeId defaultMode; bool allowGroupSwitching; float primaryFpsMin; float primaryFpsMax; @@ -355,8 +352,9 @@ TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result); ASSERT_EQ(NO_ERROR, error); bool hasWideColorMode = false; - Vector colorModes; - SurfaceComposerClient::getDisplayColorModes(display, &colorModes); + ui::DynamicDisplayInfo info; + SurfaceComposerClient::getDynamicDisplayInfo(display, &info); + const auto& colorModes = info.supportedColorModes; for (ColorMode colorMode : colorModes) { switch (colorMode) { case ColorMode::DISPLAY_P3: @@ -384,7 +382,9 @@ TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) { TEST_F(CredentialsTest, GetActiveColorModeBasicCorrectness) { const auto display = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_FALSE(display == nullptr); - ColorMode colorMode = SurfaceComposerClient::getActiveColorMode(display); + ui::DynamicDisplayInfo info; + SurfaceComposerClient::getDynamicDisplayInfo(display, &info); + ColorMode colorMode = info.activeColorMode; ASSERT_NE(static_cast(BAD_VALUE), colorMode); } diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp index 9f025a6aaa..2dc96b8511 100644 --- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp +++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -38,7 +39,7 @@ namespace android { */ class RefreshRateRangeTest : public ::testing::Test { private: - size_t initialDefaultMode; + ui::DisplayModeId initialDefaultMode; bool initialAllowGroupSwitching; float initialPrimaryMin; float initialPrimaryMax; @@ -76,20 +77,21 @@ protected: }; TEST_F(RefreshRateRangeTest, setAllConfigs) { - Vector modes; - status_t res = SurfaceComposerClient::getDisplayModes(mDisplayToken, &modes); + ui::DynamicDisplayInfo info; + status_t res = SurfaceComposerClient::getDynamicDisplayInfo(mDisplayToken, &info); + const auto& modes = info.supportedDisplayModes; ASSERT_EQ(res, NO_ERROR); ASSERT_GT(modes.size(), 0); for (size_t i = 0; i < modes.size(); i++) { - res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, i, false, + res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, modes[i].id, false, modes[i].refreshRate, modes[i].refreshRate, modes[i].refreshRate, modes[i].refreshRate); ASSERT_EQ(res, NO_ERROR); - size_t defaultConfig; + ui::DisplayModeId defaultConfig; bool allowGroupSwitching; float primaryRefreshRateMin; float primaryRefreshRateMax; @@ -116,7 +118,7 @@ void RefreshRateRangeTest::testSetAllowGroupSwitching(bool allowGroupSwitching) SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, 0, allowGroupSwitching, 0.f, 90.f, 0.f, 90.f); ASSERT_EQ(res, NO_ERROR); - size_t defaultConfig; + ui::DisplayModeId defaultConfig; bool newAllowGroupSwitching; float primaryRefreshRateMin; float primaryRefreshRateMax; diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 56e1ae90c3..11bd9ebbb8 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -432,8 +433,9 @@ protected: } } - Vector modes; - EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes)); + ui::DynamicDisplayInfo info; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info)); + const auto& modes = info.supportedDisplayModes; EXPECT_EQ(modes.size(), 2); // change active mode @@ -539,8 +541,9 @@ protected: } } - Vector modes; - EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes)); + ui::DynamicDisplayInfo info; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info)); + const auto& modes = info.supportedDisplayModes; EXPECT_EQ(modes.size(), 2); // change active mode @@ -655,8 +658,9 @@ protected: } } - Vector modes; - EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes)); + ui::DynamicDisplayInfo info; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info)); + const auto& modes = info.supportedDisplayModes; EXPECT_EQ(modes.size(), 4); // change active mode to 800x1600@90Hz @@ -884,8 +888,9 @@ protected: EXPECT_EQ(ui::Size(800, 1600), mode.resolution); EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate); - Vector modes; - EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes)); + ui::DynamicDisplayInfo info; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info)); + const auto& modes = info.supportedDisplayModes; EXPECT_EQ(modes.size(), 1); } @@ -923,8 +928,9 @@ protected: EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate); } - Vector modes; - EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes)); + ui::DynamicDisplayInfo info; + EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDynamicDisplayInfo(display, &info)); + const auto& modes = info.supportedDisplayModes; EXPECT_EQ(modes.size(), 3); EXPECT_EQ(ui::Size(800, 1600), modes[0].resolution); diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index b696a6d51b..256be27b2d 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -286,7 +286,7 @@ struct BaseDisplayVariant { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder() - .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setIsSecure(Derived::IS_SECURE) .setLayerStackId(DEFAULT_LAYER_STACK) @@ -300,7 +300,7 @@ struct BaseDisplayVariant { ceDisplayArgs); test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - DisplayConnectionType::Internal, HWC_DISPLAY, + ui::DisplayConnectionType::Internal, HWC_DISPLAY, true /* isPrimary */) .setDisplaySurface(test->mDisplaySurface) .setNativeWindow(test->mNativeWindow) diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 90692003ef..a3e810871c 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -139,14 +139,14 @@ sp DisplayTransactionTest::injectDefaultInternalDisplay( createDisplay(mFlinger.getCompositionEngine(), compositionengine::DisplayCreationArgsBuilder() .setPhysical( - {DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal}) + {DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal}) .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT}) .setPowerAdvisor(&mPowerAdvisor) .build()); - auto injector = - FakeDisplayDeviceInjector(mFlinger, compositionDisplay, DisplayConnectionType::Internal, - DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */); + auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, + ui::DisplayConnectionType::Internal, + DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */); injector.setNativeWindow(mNativeWindow); if (injectExtra) { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index 166430193d..d68fff6345 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -202,12 +202,13 @@ struct DisplayIdGetter { template struct DisplayConnectionTypeGetter { - static constexpr std::optional value; + static constexpr std::optional value; }; template struct DisplayConnectionTypeGetter> { - static constexpr std::optional value = PhysicalDisplay::CONNECTION_TYPE; + static constexpr std::optional value = + PhysicalDisplay::CONNECTION_TYPE; }; template @@ -263,7 +264,7 @@ struct DisplayVariant { static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder(); if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) { - ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal}); + ceDisplayArgs.setPhysical({*displayId, ui::DisplayConnectionType::Internal}); } else { // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine // from calling into HWComposer. This way all virtual displays will get @@ -457,7 +458,7 @@ struct HwcDisplayVariant { static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) { constexpr auto CONNECTION_TYPE = - PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal + PhysicalDisplay::CONNECTION_TYPE == ui::DisplayConnectionType::Internal ? IComposerClient::DisplayConnectionType::INTERNAL : IComposerClient::DisplayConnectionType::EXTERNAL; @@ -504,7 +505,7 @@ struct PhysicalDisplayVariant template struct PrimaryDisplay { - static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal; + static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::Internal; static constexpr Primary PRIMARY = Primary::TRUE; static constexpr uint8_t PORT = 255; static constexpr HWDisplayId HWC_DISPLAY_ID = 1001; @@ -514,7 +515,7 @@ struct PrimaryDisplay { template struct ExternalDisplay { - static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External; + static constexpr auto CONNECTION_TYPE = ui::DisplayConnectionType::External; static constexpr Primary PRIMARY = Primary::FALSE; static constexpr uint8_t PORT = 254; static constexpr HWDisplayId HWC_DISPLAY_ID = 1002; diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index dee13d6e8d..2ba6490cd7 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -634,7 +634,7 @@ public: public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, std::shared_ptr compositionDisplay, - std::optional connectionType, + std::optional connectionType, std::optional hwcDisplayId, bool isPrimary) : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(), -- cgit v1.2.3-59-g8ed1b From c5986778d0d6c7ab3f96fafb1b84887e901ed92b Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 16 Mar 2021 16:09:49 +0100 Subject: setFrameRate: Make shouldBeSeamless an enum Change the shouldBeSeamless parameter to an enum in order to make the API easier to understand. This changes - SurfaceControl.setFrameRate - Surface.setFrameRate - ANativeWindow_setFrameRateWithChangeStrategy - ASurfaceTransaction_setFrameRateWithChangeStrategy Bug: 179116474 Test: atest SetFrameRateTest Change-Id: I28a8863ea77101f90b878fbda5f00d98e075b7cc --- include/android/surface_control.h | 18 +++-- libs/gui/BLASTBufferQueue.cpp | 8 ++- libs/gui/ISurfaceComposer.cpp | 76 ++++++---------------- libs/gui/LayerState.cpp | 19 ++++-- libs/gui/Surface.cpp | 12 ++-- libs/gui/SurfaceComposerClient.cpp | 7 +- libs/gui/include/gui/ISurfaceComposer.h | 2 +- libs/gui/include/gui/LayerState.h | 7 +- libs/gui/include/gui/Surface.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 2 +- libs/gui/tests/Surface_test.cpp | 2 +- libs/nativewindow/ANativeWindow.cpp | 10 +-- libs/nativewindow/include/android/native_window.h | 31 ++++++--- libs/nativewindow/include/system/window.h | 4 +- libs/nativewindow/libnativewindow.map.txt | 2 +- services/surfaceflinger/Layer.cpp | 12 ++++ services/surfaceflinger/Layer.h | 13 ++-- services/surfaceflinger/SurfaceFlinger.cpp | 26 +++++--- services/surfaceflinger/SurfaceFlinger.h | 2 +- .../tests/unittests/SetFrameRateTest.cpp | 38 ++++++++--- 20 files changed, 159 insertions(+), 135 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/include/android/surface_control.h b/include/android/surface_control.h index c17f8224c2..26b63d2005 100644 --- a/include/android/surface_control.h +++ b/include/android/surface_control.h @@ -420,10 +420,10 @@ void ASurfaceTransaction_setHdrMetadata_cta861_3(ASurfaceTransaction* transactio __INTRODUCED_IN(29); /** - * Same as ASurfaceTransaction_setFrameRateWithSeamlessness(transaction, surface_control, - * frameRate, compatibility, true). + * Same as ASurfaceTransaction_setFrameRateWithChangeStrategy(transaction, surface_control, + * frameRate, compatibility, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS). * - * See ASurfaceTransaction_setFrameRateWithSeamlessness(). + * See ASurfaceTransaction_setFrameRateWithChangeStrategy(). * * Available since API level 30. */ @@ -451,17 +451,15 @@ void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* transaction, * influence the system's choice of display frame rate. To specify a compatibility use the * ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* enum. * - * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A - * seamless transition is one that doesn't have any visual interruptions, such as a black - * screen for a second or two. True indicates that any frame rate changes caused by this - * request should be seamless. False indicates that non-seamless refresh rates are also - * acceptable. + * \param changeFrameRateStrategy Whether display refresh rate transitions should be seamless. + * A seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. See the ANATIVEWINDOW_CHANGE_FRAME_RATE_* values. * * Available since API level 31. */ -void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* transaction, +void ASurfaceTransaction_setFrameRateWithChangeStrategy(ASurfaceTransaction* transaction, ASurfaceControl* surface_control, float frameRate, - int8_t compatibility, bool shouldBeSeamless) + int8_t compatibility, int8_t changeFrameRateStrategy) __INTRODUCED_IN(31); __END_DECLS diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 82c9268feb..3f545b25e5 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -544,11 +544,13 @@ public: }).detach(); } - status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) override { - if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) { + status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override { + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "BBQSurface::setFrameRate")) { return BAD_VALUE; } - return mBbq->setFrameRate(frameRate, compatibility, shouldBeSeamless); + return mBbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy); } status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f44f10a2ce..71215fef36 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1012,39 +1012,15 @@ public: } status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) override { + int8_t compatibility, int8_t changeFrameRateStrategy) override { Parcel data, reply; - status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing interface token: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeStrongBinder(IInterface::asBinder(surface)); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing strong binder: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeFloat(frameRate); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing float: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeByte(compatibility); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing byte: %s (%d)", strerror(-err), -err); - return err; - } - - err = data.writeBool(shouldBeSeamless); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed writing bool: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(surface)); + SAFE_PARCEL(data.writeFloat, frameRate); + SAFE_PARCEL(data.writeByte, compatibility); + SAFE_PARCEL(data.writeByte, changeFrameRateStrategy); - err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); + status_t err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); if (err != NO_ERROR) { ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); return err; @@ -1873,36 +1849,24 @@ status_t BnSurfaceComposer::onTransact( case SET_FRAME_RATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp binder; - status_t err = data.readStrongBinder(&binder); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read strong binder: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(data.readStrongBinder, &binder); + sp surface = interface_cast(binder); if (!surface) { - ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer: %s (%d)", - strerror(-err), -err); - return err; + ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer"); + return BAD_VALUE; } float frameRate; - err = data.readFloat(&frameRate); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read float: %s (%d)", strerror(-err), -err); - return err; - } + SAFE_PARCEL(data.readFloat, &frameRate); + int8_t compatibility; - err = data.readByte(&compatibility); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read byte: %s (%d)", strerror(-err), -err); - return err; - } - bool shouldBeSeamless; - err = data.readBool(&shouldBeSeamless); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to read bool: %s (%d)", strerror(-err), -err); - return err; - } - status_t result = setFrameRate(surface, frameRate, compatibility, shouldBeSeamless); + SAFE_PARCEL(data.readByte, &compatibility); + + int8_t changeFrameRateStrategy; + SAFE_PARCEL(data.readByte, &changeFrameRateStrategy); + + status_t result = + setFrameRate(surface, frameRate, compatibility, changeFrameRateStrategy); reply->writeInt32(result); return NO_ERROR; } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 04a878563e..2c4dfc54f3 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -60,7 +61,7 @@ layer_state_t::layer_state_t() frameRateSelectionPriority(-1), frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), - shouldBeSeamless(true), + changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), fixedTransformHint(ui::Transform::ROT_INVALID), frameNumber(0), frameTimelineInfo(), @@ -148,7 +149,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeInt32, frameRateSelectionPriority); SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); - SAFE_PARCEL(output.writeBool, shouldBeSeamless); + SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeUint64, frameNumber); SAFE_PARCEL(frameTimelineInfo.write, output); @@ -269,7 +270,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readInt32, &frameRateSelectionPriority); SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); - SAFE_PARCEL(input.readBool, &shouldBeSeamless); + SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast(tmpUint32); SAFE_PARCEL(input.readUint64, &frameNumber); @@ -526,7 +527,7 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eFrameRateChanged; frameRate = other.frameRate; frameRateCompatibility = other.frameRateCompatibility; - shouldBeSeamless = other.shouldBeSeamless; + changeFrameRateStrategy = other.changeFrameRateStrategy; } if (other.what & eFixedTransformHintChanged) { what |= eFixedTransformHintChanged; @@ -616,8 +617,8 @@ status_t InputWindowCommands::read(const Parcel& input) { return NO_ERROR; } -bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunctionName, - bool privileged) { +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* inFunctionName, bool privileged) { const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; int floatClassification = std::fpclassify(frameRate); if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { @@ -633,6 +634,12 @@ bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* inFunc return false; } + if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS && + changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) { + ALOGE("%s failed - invalid change frame rate strategy value %d", functionName, + changeFrameRateStrategy); + } + return true; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 6de3e971b2..2fc9d47b89 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1729,8 +1729,8 @@ int Surface::dispatchGetLastQueueDuration(va_list args) { int Surface::dispatchSetFrameRate(va_list args) { float frameRate = static_cast(va_arg(args, double)); int8_t compatibility = static_cast(va_arg(args, int)); - bool shouldBeSeamless = static_cast(va_arg(args, int)); - return setFrameRate(frameRate, compatibility, shouldBeSeamless); + int8_t changeFrameRateStrategy = static_cast(va_arg(args, int)); + return setFrameRate(frameRate, compatibility, changeFrameRateStrategy); } int Surface::dispatchAddCancelInterceptor(va_list args) { @@ -2575,16 +2575,18 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vectoronBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { ATRACE_CALL(); ALOGV("Surface::setFrameRate"); - if (!ValidateFrameRate(frameRate, compatibility, "Surface::setFrameRate")) { + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "Surface::setFrameRate")) { return BAD_VALUE; } return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility, - shouldBeSeamless); + changeFrameRateStrategy); } status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 18a0cbd1c0..3c10858dfe 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1511,7 +1511,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShado SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( const sp& sc, float frameRate, int8_t compatibility, - bool shouldBeSeamless) { + int8_t changeFrameRateStrategy) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; @@ -1519,7 +1519,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame } // Allow privileged values as well here, those will be ignored by SF if // the caller is not privileged - if (!ValidateFrameRate(frameRate, compatibility, "Transaction::setFrameRate", + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "Transaction::setFrameRate", /*privileged=*/true)) { mStatus = BAD_VALUE; return *this; @@ -1527,7 +1528,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; s->frameRateCompatibility = compatibility; - s->shouldBeSeamless = shouldBeSeamless; + s->changeFrameRateStrategy = changeFrameRateStrategy; return *this; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 88cfe4b9ac..3cf9a733b6 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -461,7 +461,7 @@ public: * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. */ virtual status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) = 0; + int8_t compatibility, int8_t changeFrameRateStrategy) = 0; /* * Acquire a frame rate flexibility token from SurfaceFlinger. While this token is acquired, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index f7a66985b7..cc8cc0d3ae 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -208,7 +208,7 @@ struct layer_state_t { // Layer frame rate and compatibility. See ANativeWindow_setFrameRate(). float frameRate; int8_t frameRateCompatibility; - bool shouldBeSeamless; + int8_t changeFrameRateStrategy; // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that @@ -305,10 +305,11 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) // // @param frameRate the frame rate in Hz // @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* +// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_* // @param functionName calling function or nullptr. Used for logging // @param privileged whether caller has unscoped surfaceflinger access -bool ValidateFrameRate(float frameRate, int8_t compatibility, const char* functionName, - bool privileged = false); +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* functionName, bool privileged = false); struct CaptureArgs { const static int32_t UNSET_UID = -1; diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 58812214d2..d22bdaaa98 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -187,7 +187,8 @@ public: status_t getUniqueId(uint64_t* outId) const; status_t getConsumerUsage(uint64_t* outUsage) const; - virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless); + virtual status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy); virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); virtual status_t getExtraBufferCount(int* extraBuffers) const; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 40c4135a51..4997e36899 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -509,7 +509,7 @@ public: Transaction& setShadowRadius(const sp& sc, float cornerRadius); Transaction& setFrameRate(const sp& sc, float frameRate, - int8_t compatibility, bool shouldBeSeamless); + int8_t compatibility, int8_t changeFrameRateStrategy); // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e8fb71dc1d..68c834de63 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -855,7 +855,7 @@ public: } status_t setFrameRate(const sp& /*surface*/, float /*frameRate*/, - int8_t /*compatibility*/, bool /*shouldBeSeamless*/) override { + int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) override { return NO_ERROR; } diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index b406a9c2fe..ada689ac42 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -159,8 +159,8 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { } int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { - return ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, - /*shouldBeSeamless*/ true); + return ANativeWindow_setFrameRateWithChangeStrategy(window, frameRate, compatibility, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); } void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { @@ -170,12 +170,12 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) { window->perform(window, NATIVE_WINDOW_ALLOCATE_BUFFERS); } -int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { +int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, float frameRate, + int8_t compatibility, int8_t changeFrameRateStrategy) { if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { return -EINVAL; } - return native_window_set_frame_rate(window, frameRate, compatibility, shouldBeSeamless); + return native_window_set_frame_rate(window, frameRate, compatibility, changeFrameRateStrategy); } /************************************************************************************************** diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 285f2fb7fe..50e9d53604 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -247,9 +247,10 @@ enum ANativeWindow_FrameRateCompatibility { }; /** - * Same as ANativeWindow_setFrameRateWithSeamlessness(window, frameRate, compatibility, true). + * Same as ANativeWindow_setFrameRateWithChangeStrategy(window, frameRate, compatibility, + * ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS). * - * See ANativeWindow_setFrameRateWithSeamlessness(). + * See ANativeWindow_setFrameRateWithChangeStrategy(). * * Available since API level 30. */ @@ -267,6 +268,19 @@ int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_ */ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30); +/** Change frame rate strategy value for ANativeWindow_setFrameRate. */ +enum ANativeWindow_ChangeFrameRateStrategy { + /** + * Change the frame rate only if the transition is going to be seamless. + */ + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS = 0, + /** + * Change the frame rate even if the transition is going to be non-seamless, + * i.e. with visual interruptions for the user. + */ + ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS = 1 +} __INTRODUCED_IN(31); + /** * Sets the intended frame rate for this window. * @@ -296,17 +310,16 @@ void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30) * compatibility value may influence the system's choice of display refresh * rate. See the ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* values for more info. * - * \param shouldBeSeamless Whether display refresh rate transitions should be seamless. A - * seamless transition is one that doesn't have any visual interruptions, such as a black - * screen for a second or two. True indicates that any frame rate changes caused by this - * request should be seamless. False indicates that non-seamless refresh rates are also - * acceptable. + * \param changeFrameRateStrategy Whether display refresh rate transitions should be seamless. + * A seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. See the ANATIVEWINDOW_CHANGE_FRAME_RATE_* values. * * \return 0 for success, -EINVAL if the window, frame rate, or compatibility * value are invalid. */ -int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate, - int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31); +int32_t ANativeWindow_setFrameRateWithChangeStrategy(ANativeWindow* window, float frameRate, + int8_t compatibility, int8_t changeFrameRateStrategy) + __INTRODUCED_IN(31); #ifdef __cplusplus }; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 7aa2cf4404..cc82bb4699 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1019,9 +1019,9 @@ static inline int native_window_set_auto_prerotation(struct ANativeWindow* windo } static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { + int8_t compatibility, int8_t changeFrameRateStrategy) { return window->perform(window, NATIVE_WINDOW_SET_FRAME_RATE, (double)frameRate, - (int)compatibility, (int)shouldBeSeamless); + (int)compatibility, (int)changeFrameRateStrategy); } static inline int native_window_set_frame_timeline_info(struct ANativeWindow* window, diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 24d0e3badc..988132cd1c 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -47,7 +47,7 @@ LIBNATIVEWINDOW { ANativeWindow_setBuffersTransform; ANativeWindow_setDequeueTimeout; # apex # introduced=30 ANativeWindow_setFrameRate; # introduced=30 - ANativeWindow_setFrameRateWithSeamlessness; # introduced=31 + ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31 ANativeWindow_setSharedBufferMode; # llndk ANativeWindow_setSwapInterval; # llndk ANativeWindow_setUsage; # llndk diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 0015bf27d1..782a7553f0 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -2864,6 +2864,18 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp } } +scheduler::Seamlessness Layer::FrameRate::convertChangeFrameRateStrategy(int8_t strategy) { + switch (strategy) { + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS: + return Seamlessness::OnlySeamless; + case ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS: + return Seamlessness::SeamedAndSeamless; + default: + LOG_ALWAYS_FATAL("Invalid change frame sate strategy value %d", strategy); + return Seamlessness::Default; + } +} + bool Layer::getPrimaryDisplayOnly() const { const State& s(mDrawingState); if (s.flags & layer_state_t::eLayerSkipScreenshot) { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 26d8e7472a..8534844a41 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -168,8 +168,9 @@ public: : rate(0), type(FrameRateCompatibility::Default), seamlessness(Seamlessness::Default) {} - FrameRate(Fps rate, FrameRateCompatibility type, bool shouldBeSeamless = true) - : rate(rate), type(type), seamlessness(getSeamlessness(rate, shouldBeSeamless)) {} + FrameRate(Fps rate, FrameRateCompatibility type, + Seamlessness seamlessness = Seamlessness::OnlySeamless) + : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {} bool operator==(const FrameRate& other) const { return rate.equalsWithMargin(other.rate) && type == other.type && @@ -181,18 +182,16 @@ public: // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid. static FrameRateCompatibility convertCompatibility(int8_t compatibility); + static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy); private: - static Seamlessness getSeamlessness(Fps rate, bool shouldBeSeamless) { + static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) { if (!rate.isValid()) { // Refresh rate of 0 is a special value which should reset the vote to // its default value. return Seamlessness::Default; - } else if (shouldBeSeamless) { - return Seamlessness::OnlySeamless; - } else { - return Seamlessness::SeamedAndSeamless; } + return seamlessness; } }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9da94832ae..7e8df89a4b 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3948,13 +3948,16 @@ uint32_t SurfaceFlinger::setClientStateLocked( } } if (what & layer_state_t::eFrameRateChanged) { - if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, - "SurfaceFlinger::setClientStateLocked", privileged) && - layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), - Layer::FrameRate::convertCompatibility( - s.frameRateCompatibility), - s.shouldBeSeamless))) { - flags |= eTraversalNeeded; + if (ValidateFrameRate(s.frameRate, s.frameRateCompatibility, s.changeFrameRateStrategy, + "SurfaceFlinger::setClientStateLocked", privileged)) { + const auto compatibility = + Layer::FrameRate::convertCompatibility(s.frameRateCompatibility); + const auto strategy = + Layer::FrameRate::convertChangeFrameRateStrategy(s.changeFrameRateStrategy); + + if (layer->setFrameRate(Layer::FrameRate(Fps(s.frameRate), compatibility, strategy))) { + flags |= eTraversalNeeded; + } } } FrameTimelineInfo info; @@ -6367,8 +6370,9 @@ const std::unordered_map& SurfaceFlinger::getGenericLayer } status_t SurfaceFlinger::setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) { - if (!ValidateFrameRate(frameRate, compatibility, "SurfaceFlinger::setFrameRate")) { + int8_t compatibility, int8_t changeFrameRateStrategy) { + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "SurfaceFlinger::setFrameRate")) { return BAD_VALUE; } @@ -6380,10 +6384,12 @@ status_t SurfaceFlinger::setFrameRate(const sp& surface, ALOGE("Attempt to set frame rate on a layer that no longer exists"); return BAD_VALUE; } + const auto strategy = + Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy); if (layer->setFrameRate( Layer::FrameRate(Fps{frameRate}, Layer::FrameRate::convertCompatibility(compatibility), - shouldBeSeamless))) { + strategy))) { setTransactionFlags(eTraversalNeeded); } } else { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 3787b9db89..65e00198b3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -685,7 +685,7 @@ private: status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) override; status_t setFrameRate(const sp& surface, float frameRate, - int8_t compatibility, bool shouldBeSeamless) override; + int8_t compatibility, int8_t changeFrameRateStrategy) override; status_t acquireFrameRateFlexibilityToken(sp* outToken) override; status_t setFrameTimelineInfo(const sp& surface, diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 5c8c2d888c..7ef1f2b378 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -475,18 +475,36 @@ INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, PrintToStringParamName); TEST_F(SetFrameRateTest, ValidateFrameRate) { - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, "", /*privileged=*/true)); - - EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); - EXPECT_FALSE( - ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", + /*privileged=*/true)); + + EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Invalid compatibility EXPECT_FALSE( - ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, "")); + ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, "")); + // Invalid change frame rate strategy + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, "")); + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, "")); } TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { -- cgit v1.2.3-59-g8ed1b From 82d07c9e4561ec7adc9340207d25b59b7926c3c9 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 10 May 2021 11:36:43 -0700 Subject: BBQSurface: Give client a chance to observe transform hint earlier The client may be observing the transform hint through the Surface.cpp codepath however Surface#mTransformHint will only be updated on queueBuffer. However imagine a scenario like this: 1. transform hint changes on server 2. queue buffer 2. repeat queue buffer 3. callback for queue buffer 1 and 2, updates transform hint on client 4. queue buffer 4 5. Client now observes transform hint 6. Queue buffer 5(!) will finally contain the transform hint. With this change we give the client a chance to observe the tranform hint in this scenario before queue buffer 4. In the case of the ScreenDecorOverlay's which rarely redraw, this seems to fix some persistent pre-rotation issues. Bug: 184842607 Test: Existing tests pass. Change-Id: I34524ee40c6076f497bb0c60af901e9c93798a48 --- libs/gui/BLASTBufferQueue.cpp | 21 +++++++++++++++++++++ libs/gui/Surface.cpp | 4 ++-- libs/gui/include/gui/BLASTBufferQueue.h | 2 ++ libs/gui/include/gui/Surface.h | 3 ++- 4 files changed, 27 insertions(+), 3 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 3d854c2b92..a023067887 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -316,6 +316,11 @@ void BLASTBufferQueue::releaseBufferCallback(uint64_t graphicBufferId, std::unique_lock _lock{mMutex}; BQA_LOGV("releaseBufferCallback graphicBufferId=%" PRIu64, graphicBufferId); + if (mSurfaceControl != nullptr) { + mTransformHint = mSurfaceControl->getTransformHint(); + mBufferItemConsumer->setTransformHint(mTransformHint); + } + auto it = mSubmitted.find(graphicBufferId); if (it == mSubmitted.end()) { BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %" PRIu64, @@ -608,6 +613,14 @@ public: status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override { return mBbq->setFrameTimelineInfo(frameTimelineInfo); } + protected: + uint32_t getTransformHint() const override { + if (mStickyTransform == 0 && !transformToDisplayInverse()) { + return mBbq->getLastTransformHint(); + } else { + return 0; + } + } }; // TODO: Can we coalesce this with frame updates? Need to confirm @@ -777,4 +790,12 @@ PixelFormat BLASTBufferQueue::convertBufferFormat(PixelFormat& format) { return convertedFormat; } +uint32_t BLASTBufferQueue::getLastTransformHint() const { + if (mSurfaceControl != nullptr) { + return mSurfaceControl->getTransformHint(); + } else { + return 0; + } +} + } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2fc9d47b89..83aaf36a8d 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1288,7 +1288,7 @@ int Surface::query(int what, int* value) const { mUserHeight ? mUserHeight : mDefaultHeight); return NO_ERROR; case NATIVE_WINDOW_TRANSFORM_HINT: - *value = static_cast(mTransformHint); + *value = static_cast(getTransformHint()); return NO_ERROR; case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: { status_t err = NO_ERROR; @@ -1822,7 +1822,7 @@ int Surface::dispatchGetExtraBufferCount(va_list args) { return getExtraBufferCount(extraBuffers); } -bool Surface::transformToDisplayInverse() { +bool Surface::transformToDisplayInverse() const { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 139dbb7f6b..c4ca399e37 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -103,6 +103,8 @@ public: void setSidebandStream(const sp& stream); + uint32_t getLastTransformHint() const; + virtual ~BLASTBufferQueue(); private: diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index d22bdaaa98..89e1909a45 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -278,7 +278,6 @@ private: int dispatchGetLastQueuedBuffer(va_list args); int dispatchSetFrameTimelineInfo(va_list args); int dispatchGetExtraBufferCount(va_list args); - bool transformToDisplayInverse(); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); @@ -490,6 +489,8 @@ protected: // mTransformHint is the transform probably applied to buffers of this // window. this is only a hint, actual transform may differ. uint32_t mTransformHint; + virtual uint32_t getTransformHint() const { return mTransformHint; } + bool transformToDisplayInverse() const; // mProducerControlledByApp whether this buffer producer is controlled // by the application -- cgit v1.2.3-59-g8ed1b From aa5a0b26bbeb37f60e091729405bd57169d1dcbc Mon Sep 17 00:00:00 2001 From: John Reck Date: Tue, 18 May 2021 00:42:56 -0400 Subject: Add a better getLastQueuedBuffer Avoid obfuscation via a matrix that's not necessarily useful or in the desired origin of the caller. Instead return the source data, which is also a lot smaller than the matrix is... Bug: 183553027 Test: atest android.view.cts.PixelCopyTest (+new testBufferQueueCrop) Change-Id: I1f7b5981405b2f20293bce9119414fc7780b8eb6 --- libs/gui/BufferQueueProducer.cpp | 20 ++++++ libs/gui/IGraphicBufferProducer.cpp | 95 +++++++++++++++++++++++++++ libs/gui/Surface.cpp | 36 ++++++++++ libs/gui/include/gui/BufferQueueProducer.h | 4 ++ libs/gui/include/gui/IGraphicBufferProducer.h | 16 +++++ libs/gui/include/gui/Surface.h | 1 + libs/nativewindow/include/system/window.h | 26 ++++++++ 7 files changed, 198 insertions(+) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index a7cf39add9..df308d897b 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -1621,6 +1621,26 @@ status_t BufferQueueProducer::getLastQueuedBuffer(sp* outBuffer, return NO_ERROR; } +status_t BufferQueueProducer::getLastQueuedBuffer(sp* outBuffer, sp* outFence, + Rect* outRect, uint32_t* outTransform) { + ATRACE_CALL(); + BQ_LOGV("getLastQueuedBuffer"); + + std::lock_guard lock(mCore->mMutex); + if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) { + *outBuffer = nullptr; + *outFence = Fence::NO_FENCE; + return NO_ERROR; + } + + *outBuffer = mSlots[mCore->mLastQueuedSlot].mGraphicBuffer; + *outFence = mLastQueueBufferFence; + *outRect = mLastQueuedCrop; + *outTransform = mLastQueuedTransform; + + return NO_ERROR; +} + void BufferQueueProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) { addAndGetFrameTimestamps(nullptr, outDelta); } diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index c1f9b85229..797069c798 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -81,6 +81,7 @@ enum { QUEUE_BUFFERS, CANCEL_BUFFERS, QUERY_MULTIPLE, + GET_LAST_QUEUED_BUFFER2, }; class BpGraphicBufferProducer : public BpInterface @@ -646,6 +647,56 @@ public: return result; } + virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, + Rect* outRect, uint32_t* outTransform) override { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + status_t result = remote()->transact(GET_LAST_QUEUED_BUFFER2, data, &reply); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to transact: %d", result); + return result; + } + status_t remoteError = NO_ERROR; + result = reply.readInt32(&remoteError); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read status: %d", result); + return result; + } + if (remoteError != NO_ERROR) { + return remoteError; + } + bool hasBuffer = false; + result = reply.readBool(&hasBuffer); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read buffer: %d", result); + return result; + } + sp buffer; + if (hasBuffer) { + buffer = new GraphicBuffer(); + result = reply.read(*buffer); + if (result == NO_ERROR) { + result = reply.read(*outRect); + } + if (result == NO_ERROR) { + result = reply.readUint32(outTransform); + } + } + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read buffer: %d", result); + return result; + } + sp fence(new Fence); + result = reply.read(*fence); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to read fence: %d", result); + return result; + } + *outBuffer = buffer; + *outFence = fence; + return result; + } + virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) { Parcel data, reply; status_t result = data.writeInterfaceToken( @@ -870,6 +921,11 @@ public: outBuffer, outFence, outTransformMatrix); } + status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, Rect* outRect, + uint32_t* outTransform) override { + return mBase->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform); + } + void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override { return mBase->getFrameTimestamps(outDelta); } @@ -1362,6 +1418,45 @@ status_t BnGraphicBufferProducer::onTransact( } return NO_ERROR; } + case GET_LAST_QUEUED_BUFFER2: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + sp buffer(nullptr); + sp fence(Fence::NO_FENCE); + Rect crop; + uint32_t transform; + status_t result = getLastQueuedBuffer(&buffer, &fence, &crop, &transform); + reply->writeInt32(result); + if (result != NO_ERROR) { + return result; + } + if (!buffer.get()) { + reply->writeBool(false); + } else { + reply->writeBool(true); + result = reply->write(*buffer); + if (result == NO_ERROR) { + result = reply->write(crop); + } + if (result == NO_ERROR) { + result = reply->writeUint32(transform); + } + } + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to write buffer: %d", result); + return result; + } + if (fence == nullptr) { + ALOGE("getLastQueuedBuffer returned a NULL fence, setting to Fence::NO_FENCE"); + fence = Fence::NO_FENCE; + } + result = reply->write(*fence); + if (result != NO_ERROR) { + ALOGE("getLastQueuedBuffer failed to write fence: %d", result); + return result; + } + return NO_ERROR; + } + case GET_FRAME_TIMESTAMPS: { CHECK_INTERFACE(IGraphicBufferProducer, data, reply); FrameEventHistoryDelta frameTimestamps; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2fc9d47b89..89e80c1808 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1492,6 +1492,9 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER: res = dispatchGetLastQueuedBuffer(args); break; + case NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2: + res = dispatchGetLastQueuedBuffer2(args); + break; case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: res = dispatchSetFrameTimelineInfo(args); break; @@ -1805,6 +1808,39 @@ int Surface::dispatchGetLastQueuedBuffer(va_list args) { return result; } +int Surface::dispatchGetLastQueuedBuffer2(va_list args) { + AHardwareBuffer** buffer = va_arg(args, AHardwareBuffer**); + int* fence = va_arg(args, int*); + ARect* crop = va_arg(args, ARect*); + uint32_t* transform = va_arg(args, uint32_t*); + sp graphicBuffer; + sp spFence; + + Rect r; + int result = + mGraphicBufferProducer->getLastQueuedBuffer(&graphicBuffer, &spFence, &r, transform); + + if (graphicBuffer != nullptr) { + *buffer = graphicBuffer->toAHardwareBuffer(); + AHardwareBuffer_acquire(*buffer); + + // Avoid setting crop* unless buffer is valid (matches IGBP behavior) + crop->left = r.left; + crop->top = r.top; + crop->right = r.right; + crop->bottom = r.bottom; + } else { + *buffer = nullptr; + } + + if (spFence != nullptr) { + *fence = spFence->dup(); + } else { + *fence = -1; + } + return result; +} + int Surface::dispatchSetFrameTimelineInfo(va_list args) { ATRACE_CALL(); auto frameTimelineVsyncId = static_cast(va_arg(args, int64_t)); diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index a7f7d1defa..0ad3075a4d 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -186,6 +186,10 @@ public: virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) override; + // See IGraphicBufferProducer::getLastQueuedBuffer + virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, + Rect* outRect, uint32_t* outTransform) override; + // See IGraphicBufferProducer::getFrameTimestamps virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override; diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index c3b92622b6..98df83453d 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -640,6 +640,22 @@ public: virtual status_t getLastQueuedBuffer(sp* outBuffer, sp* outFence, float outTransformMatrix[16]) = 0; + // Returns the last queued buffer along with a fence which must signal + // before the contents of the buffer are read. If there are no buffers in + // the queue, outBuffer will be populated with nullptr and outFence will be + // populated with Fence::NO_FENCE + // + // outRect & outTransform are not modified if outBuffer is null. + // + // Returns NO_ERROR or the status of the Binder transaction + virtual status_t getLastQueuedBuffer([[maybe_unused]] sp* outBuffer, + [[maybe_unused]] sp* outFence, + [[maybe_unused]] Rect* outRect, + [[maybe_unused]] uint32_t* outTransform) { + // Too many things implement IGraphicBufferProducer... + return UNKNOWN_TRANSACTION; + } + // Gets the frame events that haven't already been retrieved. virtual void getFrameTimestamps(FrameEventHistoryDelta* /*outDelta*/) {} diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index d22bdaaa98..250e13fe26 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -276,6 +276,7 @@ private: int dispatchAddQueueInterceptor(va_list args); int dispatchAddQueryInterceptor(va_list args); int dispatchGetLastQueuedBuffer(va_list args); + int dispatchGetLastQueuedBuffer2(va_list args); int dispatchSetFrameTimelineInfo(va_list args); int dispatchGetExtraBufferCount(va_list args); bool transformToDisplayInverse(); diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index cc82bb4699..935eded983 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -257,6 +257,7 @@ enum { NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT = 49, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 50, /* private */ // clang-format on }; @@ -1066,6 +1067,31 @@ static inline int ANativeWindow_getLastQueuedBuffer(ANativeWindow* window, outTransformMatrix); } +/** + * Retrieves the last queued buffer for this window, along with the fence that + * fires when the buffer is ready to be read. The cropRect & transform should be applied to the + * buffer's content. + * + * If there was no buffer previously queued, then outBuffer will be NULL and + * the value of outFence will be -1. + * + * Note that if outBuffer is not NULL, then the caller will hold a reference + * onto the buffer. Accordingly, the caller must call AHardwareBuffer_release + * when the buffer is no longer needed so that the system may reclaim the + * buffer. + * + * \return NO_ERROR on success. + * \return NO_MEMORY if there was insufficient memory. + * \return STATUS_UNKNOWN_TRANSACTION if this ANativeWindow doesn't support this method, callers + * should fall back to ANativeWindow_getLastQueuedBuffer instead. + */ +static inline int ANativeWindow_getLastQueuedBuffer2(ANativeWindow* window, + AHardwareBuffer** outBuffer, int* outFence, + ARect* outCropRect, uint32_t* outTransform) { + return window->perform(window, NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2, outBuffer, outFence, + outCropRect, outTransform); +} + /** * Retrieves an identifier for the next frame to be queued by this window. * -- cgit v1.2.3-59-g8ed1b From 9b85a194e4118819b2bd9ab0bfb489f78ae1b529 Mon Sep 17 00:00:00 2001 From: Brian Lindahl Date: Mon, 10 May 2021 09:56:33 +0000 Subject: Add robustness for permissions errors to Surface APIs. Test: Tested ag/14424498 via testHevcTranscodingWithFileDescriptor on Test: flame - ab/builds/forrest/run/L38000000884507245 Bug: 184903653 Bug: 184112407 Change-Id: I94dcaa31edcf0f810c6cf69ca6e73277470fa51f --- libs/gui/Surface.cpp | 7 +++++-- libs/gui/SurfaceComposerClient.cpp | 15 ++++++++------- libs/gui/include/private/gui/ComposerService.h | 5 ++--- 3 files changed, 15 insertions(+), 12 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 2fc9d47b89..f4aa7b3d8b 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1268,8 +1268,11 @@ int Surface::query(int what, int* value) const { if (err == NO_ERROR) { return NO_ERROR; } - if (composerService()->authenticateSurfaceTexture( - mGraphicBufferProducer)) { + sp surfaceComposer = composerService(); + if (surfaceComposer == nullptr) { + return -EPERM; // likely permissions error + } + if (surfaceComposer->authenticateSurfaceTexture(mGraphicBufferProducer)) { *value = 1; } else { *value = 0; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 808b731d8f..0656dae6fb 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -65,12 +65,12 @@ ComposerService::ComposerService() connectLocked(); } -void ComposerService::connectLocked() { +bool ComposerService::connectLocked() { const String16 name("SurfaceFlinger"); - while (getService(name, &mComposerService) != NO_ERROR) { - usleep(250000); + mComposerService = waitForService(name); + if (mComposerService == nullptr) { + return false; // fatal error or permission problem } - assert(mComposerService != nullptr); // Create the death listener. class DeathObserver : public IBinder::DeathRecipient { @@ -86,15 +86,16 @@ void ComposerService::connectLocked() { mDeathObserver = new DeathObserver(*const_cast(this)); IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); + return true; } /*static*/ sp ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); if (instance.mComposerService == nullptr) { - ComposerService::getInstance().connectLocked(); - assert(instance.mComposerService != nullptr); - ALOGD("ComposerService reconnected"); + if (ComposerService::getInstance().connectLocked()) { + ALOGD("ComposerService reconnected"); + } } return instance.mComposerService; } diff --git a/libs/gui/include/private/gui/ComposerService.h b/libs/gui/include/private/gui/ComposerService.h index 50bd742b6a..fa1071a4e3 100644 --- a/libs/gui/include/private/gui/ComposerService.h +++ b/libs/gui/include/private/gui/ComposerService.h @@ -45,13 +45,12 @@ class ComposerService : public Singleton Mutex mLock; ComposerService(); - void connectLocked(); + bool connectLocked(); void composerServiceDied(); friend class Singleton; public: - // Get a connection to the Composer Service. This will block until - // a connection is established. + // a connection is established. Returns null if permission is denied. static sp getComposerService(); }; -- cgit v1.2.3-59-g8ed1b From 0bde6b5a9837ab96484c988bb3f148d0b9b3ab4e Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Tue, 18 May 2021 13:57:02 -0700 Subject: SF: increase the number of buffers for SurfaceView 3 buffers are not sufficient for most apps to render at high refresh rates. This change increases the maxAcquiredBufferCount on the buffer queue for all surfaces, and removes the hwui-specific extra buffer allocations. All Surfaces connected to SurfaceFlinger will have now enough buffers to account for configured 'debug.sf.late.app.duration' value. Test: Run backpressure based game on 60Hz and 120Hz and collect traces Bug: 188553729 Change-Id: Ib8fda5db3f48c3bfc6fbf07167b4313674512cee --- libs/gui/BLASTBufferQueue.cpp | 10 ++++++++-- libs/gui/Surface.cpp | 15 --------------- libs/gui/SurfaceControl.cpp | 2 +- libs/gui/include/gui/BLASTBufferQueue.h | 2 +- libs/gui/include/gui/Surface.h | 2 -- libs/gui/tests/BLASTBufferQueue_test.cpp | 6 +++++- libs/nativewindow/include/system/window.h | 8 +------- 7 files changed, 16 insertions(+), 29 deletions(-) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index b9a293f4c3..8024482531 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -29,9 +29,10 @@ #include #include #include - #include +#include + #include using namespace std::chrono_literals; @@ -158,6 +159,11 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const spsetDefaultBufferFormat(convertBufferFormat(format)); mBufferItemConsumer->setBlastBufferQueue(this); + int extraBufferCount = 0; + ComposerService::getComposerService()->getExtraBufferCount(&extraBufferCount); + mMaxAcquiredBuffers = 1 + extraBufferCount; + mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); + mTransformHint = mSurfaceControl->getTransformHint(); mBufferItemConsumer->setTransformHint(mTransformHint); SurfaceComposerClient::Transaction() @@ -567,7 +573,7 @@ void BLASTBufferQueue::setTransactionCompleteCallback( // includeExtraAcquire is true to include this buffer to the count. Since this depends on the state // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE. bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const { - int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1); + int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1); return mNumAcquired == maxAcquiredBuffers; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index e117d1189c..821ec16eb1 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -1501,9 +1501,6 @@ int Surface::perform(int operation, va_list args) case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO: res = dispatchSetFrameTimelineInfo(args); break; - case NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT: - res = dispatchGetExtraBufferCount(args); - break; default: res = NAME_NOT_FOUND; break; @@ -1853,14 +1850,6 @@ int Surface::dispatchSetFrameTimelineInfo(va_list args) { return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId}); } -int Surface::dispatchGetExtraBufferCount(va_list args) { - ATRACE_CALL(); - auto extraBuffers = static_cast(va_arg(args, int*)); - - ALOGV("Surface::dispatchGetExtraBufferCount"); - return getExtraBufferCount(extraBuffers); -} - bool Surface::transformToDisplayInverse() const { return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) == NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; @@ -2632,8 +2621,4 @@ status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInf return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); } -status_t Surface::getExtraBufferCount(int* extraBuffers) const { - return composerService()->getExtraBufferCount(extraBuffers); -} - }; // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index d7c07b9755..6529a4e51c 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -139,7 +139,7 @@ sp SurfaceControl::generateSurfaceLocked() ISurfaceComposerClient::eOpaque); mBbqChild = mClient->createSurface(String8("bbq-wrapper"), 0, 0, mFormat, flags, mHandle, {}, &ignore); - mBbq = new BLASTBufferQueue("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); + mBbq = sp::make("bbq-adapter", mBbqChild, mWidth, mHeight, mFormat); // This surface is always consumed by SurfaceFlinger, so the // producerControlledByApp value doesn't matter; using false. diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 3ab1ee103d..d63425e41b 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -132,7 +132,7 @@ private: // BufferQueue internally allows 1 more than // the max to be acquired - static const int MAX_ACQUIRED_BUFFERS = 1; + int32_t mMaxAcquiredBuffers = 1; int32_t mNumFrameAvailable GUARDED_BY(mMutex); int32_t mNumAcquired GUARDED_BY(mMutex); diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 48885ebdbb..7e4143b1f3 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -190,7 +190,6 @@ public: virtual status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy); virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info); - virtual status_t getExtraBufferCount(int* extraBuffers) const; protected: virtual ~Surface(); @@ -278,7 +277,6 @@ private: int dispatchGetLastQueuedBuffer(va_list args); int dispatchGetLastQueuedBuffer2(va_list args); int dispatchSetFrameTimelineInfo(va_list args); - int dispatchGetExtraBufferCount(va_list args); protected: virtual int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd); diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index 5a5da97599..06660b8b50 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -394,7 +394,11 @@ TEST_F(BLASTBufferQueueTest, TripleBuffering) { setUpProducer(adapter, igbProducer); std::vector>> allocated; - for (int i = 0; i < 3; i++) { + int minUndequeuedBuffers = 0; + ASSERT_EQ(OK, igbProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers)); + const auto bufferCount = minUndequeuedBuffers + 2; + + for (int i = 0; i < bufferCount; i++) { int slot; sp fence; sp buf; diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index 935eded983..7f0113500d 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -256,8 +256,7 @@ enum { NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER = 46, /* private */ NATIVE_WINDOW_SET_QUERY_INTERCEPTOR = 47, /* private */ NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO = 48, /* private */ - NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT = 49, /* private */ - NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 50, /* private */ + NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER2 = 49, /* private */ // clang-format on }; @@ -1032,11 +1031,6 @@ static inline int native_window_set_frame_timeline_info(struct ANativeWindow* wi frameTimelineVsyncId, inputEventId); } -static inline int native_window_get_extra_buffer_count( - struct ANativeWindow* window, int* extraBuffers) { - return window->perform(window, NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT, extraBuffers); -} - // ------------------------------------------------------------------------------------------------ // Candidates for APEX visibility // These functions are planned to be made stable for APEX modules, but have not -- cgit v1.2.3-59-g8ed1b From 1d29826112417ee5edc9bf3d51741fbdd72b2524 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Fri, 16 Jul 2021 11:17:09 -0700 Subject: Surface: Initialize mAutoPrerotation Hoping to fix the remaining buffer rejection issues. BBQ was rejecting all buffers coming from a rotated app. The logs indicated this was because Surface and BufferQueue autoPreRotation state was mismatched, resulting in BufferQueue dequeueing buffers of the wrong size. Test: presubmit Bug: 191841127 Change-Id: I84b6b8c372b49e885e5831155f8a37ae7404e6d7 --- libs/gui/Surface.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'libs/gui/Surface.cpp') diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 821ec16eb1..2edb4e4ba4 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -70,6 +70,7 @@ Surface::Surface(const sp& bufferProducer, bool controll mGenerationNumber(0), mSharedBufferMode(false), mAutoRefresh(false), + mAutoPrerotation(false), mSharedBufferSlot(BufferItem::INVALID_BUFFER_SLOT), mSharedBufferHasBeenQueued(false), mQueriedSupportedTimestamps(false), -- cgit v1.2.3-59-g8ed1b