diff options
86 files changed, 2164 insertions, 884 deletions
@@ -1,3 +1,3 @@ -third_party { + third_party { license_type: NOTICE } diff --git a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp index b1c6940207..50ea0c7e44 100644 --- a/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp +++ b/cmds/installd/tests/fuzzers/InstalldServiceFuzzer.cpp @@ -47,6 +47,8 @@ bool force_compile_without_image() { } // namespace android extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE. + signal(SIGPIPE, SIG_IGN); auto service = sp<InstalldNativeService>::make(); fuzzService(service, FuzzedDataProvider(data, size)); return 0; diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp index 809872417d..6e2abf65e2 100644 --- a/cmds/servicemanager/Access.cpp +++ b/cmds/servicemanager/Access.cpp @@ -34,7 +34,9 @@ constexpr bool kIsVendor = false; #ifdef __ANDROID__ static std::string getPidcon(pid_t pid) { - android_errorWriteLog(0x534e4554, "121035042"); + CHECK_EQ(nullptr, IPCThreadState::self()->getServingStackPointer()) + << "Did not get context from PID " << pid + << ". We should always get contexts from other processes."; char* lookup = nullptr; if (getpidcon(pid, &lookup) < 0) { diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index c126e91373..df5a8ed0d1 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -165,6 +165,7 @@ int main(int argc, char** argv) { IPCThreadState::self()->disableBackgroundScheduling(true); sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>()); + manager->setRequestingSid(true); if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) { LOG(ERROR) << "Could not self register servicemanager"; } diff --git a/include/android/looper.h b/include/android/looper.h index 8cf13965bb..409db848f8 100644 --- a/include/android/looper.h +++ b/include/android/looper.h @@ -106,7 +106,7 @@ enum { /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * An error occurred. The poll may also have been explicitly woken by - * ALooper_wake(()). + * ALooper_wake(). */ ALOOPER_POLL_ERROR = -4, }; @@ -224,11 +224,11 @@ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa * hidden and callers should migrate to ALooper_pollOnce. Binary compatibility * is preserved to support already-compiled apps. * - * \bug ALooper_pollAll will not wake in response to ALooper_wake calls if it + * \bug ALooper_pollAll() will not wake in response to ALooper_wake() calls if it * also handles another event at the same time. * - * \deprecated Calls to ALooper_pollAll should be replaced with - * ALooper_pollOnce. If you call ALooper_pollOnce in a loop, you *must* treat + * \deprecated Calls to ALooper_pollAll() should be replaced with + * ALooper_pollOnce(). If you call ALooper_pollOnce() in a loop, you *must* treat * all return values as if they also indicate ALOOPER_POLL_WAKE. */ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) @@ -242,7 +242,7 @@ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outDat * This method can be called on any thread. * This method returns immediately. * - * \bug ALooper_pollAll will not reliably wake in response to ALooper_wake. + * \bug ALooper_pollAll() will not reliably wake in response to ALooper_wake(). */ void ALooper_wake(ALooper* looper); diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index 2b4a5f5f53..9ea6549e8a 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -478,8 +478,13 @@ void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* _Nonnull aWorkDurati /** * Return the APerformanceHintSession wrapped by a Java PerformanceHintManager.Session object. * - * The Java session maintains ownership over the wrapped native session, so it cannot be - * closed using {@link APerformanceHint_closeSession}. + * The Java session maintains ownership over the wrapped native session, so it cannot be closed + * using {@link APerformanceHint_closeSession}. The return value is valid until the Java object + * containing this value dies. + * + * The returned pointer is intended to be used by JNI calls to access native performance APIs using + * a Java hint session wrapper, and then immediately discarded. Using the pointer after the death of + * the Java container results in undefined behavior. * * @param env The Java environment where the PerformanceHintManager.Session lives. * @param sessionObj The Java Session to unwrap. diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 03d687a9cc..34d5a09948 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -132,6 +132,7 @@ bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName.c_str()); return false; } + if (kRemoveStaticList) return true; for (const char* name : kStaticCachableList) { if (name == serviceName) { return true; @@ -175,7 +176,7 @@ Status BackendUnifiedServiceManager::updateCache(const std::string& serviceName, "isBinderAlive_false"); } // If we reach here with kRemoveStaticList=true then we know service isn't lazy - else if (kRemoveStaticList || mCacheForGetService->isClientSideCachingEnabled(serviceName)) { + else if (mCacheForGetService->isClientSideCachingEnabled(serviceName)) { binder::ScopedTrace aidlTrace(ATRACE_TAG_AIDL, "BinderCacheWithInvalidation::updateCache successful"); return mCacheForGetService->setItem(serviceName, binder); diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h index 65cdcd7735..b3a2d9ec28 100644 --- a/libs/binder/binder_module.h +++ b/libs/binder/binder_module.h @@ -32,34 +32,4 @@ #include <linux/android/binder.h> #include <sys/ioctl.h> -struct binder_frozen_state_info { - binder_uintptr_t cookie; - __u32 is_frozen; -}; - -#ifndef BR_FROZEN_BINDER -// Temporary definition of BR_FROZEN_BINDER until UAPI binder.h includes it. -#define BR_FROZEN_BINDER _IOR('r', 21, struct binder_frozen_state_info) -#endif // BR_FROZEN_BINDER - -#ifndef BR_CLEAR_FREEZE_NOTIFICATION_DONE -// Temporary definition of BR_CLEAR_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it. -#define BR_CLEAR_FREEZE_NOTIFICATION_DONE _IOR('r', 22, binder_uintptr_t) -#endif // BR_CLEAR_FREEZE_NOTIFICATION_DONE - -#ifndef BC_REQUEST_FREEZE_NOTIFICATION -// Temporary definition of BC_REQUEST_FREEZE_NOTIFICATION until UAPI binder.h includes it. -#define BC_REQUEST_FREEZE_NOTIFICATION _IOW('c', 19, struct binder_handle_cookie) -#endif // BC_REQUEST_FREEZE_NOTIFICATION - -#ifndef BC_CLEAR_FREEZE_NOTIFICATION -// Temporary definition of BC_CLEAR_FREEZE_NOTIFICATION until UAPI binder.h includes it. -#define BC_CLEAR_FREEZE_NOTIFICATION _IOW('c', 20, struct binder_handle_cookie) -#endif // BC_CLEAR_FREEZE_NOTIFICATION - -#ifndef BC_FREEZE_NOTIFICATION_DONE -// Temporary definition of BC_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it. -#define BC_FREEZE_NOTIFICATION_DONE _IOW('c', 21, binder_uintptr_t) -#endif // BC_FREEZE_NOTIFICATION_DONE - #endif // _BINDER_MODULE_H_ diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 30e005c2d2..5924a2d878 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -220,8 +220,6 @@ constexpr const char* const kManualInterfaces[] = { "android.app.IActivityManager", "android.app.IUidObserver", "android.drm.IDrm", - "android.dvr.IVsyncCallback", - "android.dvr.IVsyncService", "android.gfx.tests.ICallback", "android.gfx.tests.IIPCTest", "android.gfx.tests.ISafeInterfaceTest", @@ -264,17 +262,12 @@ constexpr const char* const kManualInterfaces[] = { "android.media.IResourceManagerService", "android.os.IComplexTypeInterface", "android.os.IPermissionController", - "android.os.IPingResponder", "android.os.IProcessInfoService", "android.os.ISchedulingPolicyService", - "android.os.IStringConstants", "android.os.storage.IObbActionListener", "android.os.storage.IStorageEventListener", "android.os.storage.IStorageManager", "android.os.storage.IStorageShutdownObserver", - "android.service.vr.IPersistentVrStateCallbacks", - "android.service.vr.IVrManager", - "android.service.vr.IVrStateCallbacks", "android.ui.ISurfaceComposer", "android.utils.IMemory", "android.utils.IMemoryHeap", @@ -286,9 +279,6 @@ constexpr const char* const kManualInterfaces[] = { "com.android.internal.os.IShellCallback", "drm.IDrmManagerService", "drm.IDrmServiceListener", - "IAAudioClient", - "IAAudioService", - "VtsFuzzer", nullptr, }; diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 9e92f95416..c038c95b07 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -43,6 +43,7 @@ #include <input/BlockingQueue.h> #include <processgroup/processgroup.h> #include <utils/Flattenable.h> +#include <utils/SystemClock.h> #include <linux/sched.h> #include <sys/epoll.h> @@ -343,7 +344,12 @@ class BinderLibTest : public ::testing::Test { } bool checkFreezeSupport() { - std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze"); + std::string path; + if (!CgroupGetAttributePathForTask("FreezerState", getpid(), &path)) { + return false; + } + + std::ifstream freezer_file(path); // Pass test on devices where the cgroup v2 freezer is not supported if (freezer_file.fail()) { return false; @@ -1837,14 +1843,6 @@ TEST_F(BinderLibTest, ThreadPoolStarted) { EXPECT_TRUE(reply.readBool()); } -size_t epochMillis() { - using std::chrono::duration_cast; - using std::chrono::milliseconds; - using std::chrono::seconds; - using std::chrono::system_clock; - return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); -} - TEST_F(BinderLibTest, HangingServices) { Parcel data, reply; sp<IBinder> server = addServer(); @@ -1853,7 +1851,7 @@ TEST_F(BinderLibTest, HangingServices) { data.writeInt32(delay); // b/266537959 - must take before taking lock, since countdown is started in the remote // process there. - size_t epochMsBefore = epochMillis(); + int64_t timeBefore = uptimeMillis(); EXPECT_THAT(server->transact(BINDER_LIB_TEST_PROCESS_TEMPORARY_LOCK, data, &reply), NO_ERROR); std::vector<std::thread> ts; for (size_t i = 0; i < kKernelThreads + 1; i++) { @@ -1867,10 +1865,10 @@ TEST_F(BinderLibTest, HangingServices) { for (auto &t : ts) { t.join(); } - size_t epochMsAfter = epochMillis(); + int64_t timeAfter = uptimeMillis(); // deadlock occurred and threads only finished after 1s passed. - EXPECT_GE(epochMsAfter, epochMsBefore + delay); + EXPECT_GE(timeAfter, timeBefore + delay); } TEST_F(BinderLibTest, BinderProxyCount) { diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 7aee90393b..38465b0de2 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -1032,7 +1032,7 @@ void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transacti std::lock_guard _lock{mMutex}; if (mLastAcquiredFrameNumber >= frameNumber) { // Apply the transaction since we have already acquired the desired frame. - t->apply(); + t->setApplyToken(mApplyToken).apply(); } else { mPendingTransactions.emplace_back(frameNumber, *t); // Clear the transaction so it can't be applied elsewhere. @@ -1232,6 +1232,11 @@ public: return OK; } + // Provide a callback for Choreographer to start buffer stuffing recovery when blocked + // on buffer release. + std::function<void()> callbackCopy = bbq->getWaitForBufferReleaseCallback(); + if (callbackCopy) callbackCopy(); + // BufferQueue has already checked if we have a free buffer. If there's an unread interrupt, // we want to ignore it. This must be done before unlocking the BufferQueue lock to ensure // we don't miss an interrupt. @@ -1344,6 +1349,16 @@ void BLASTBufferQueue::setApplyToken(sp<IBinder> applyToken) { mApplyToken = std::move(applyToken); } +void BLASTBufferQueue::setWaitForBufferReleaseCallback(std::function<void()> callback) { + std::lock_guard _lock{mWaitForBufferReleaseMutex}; + mWaitForBufferReleaseCallback = std::move(callback); +} + +std::function<void()> BLASTBufferQueue::getWaitForBufferReleaseCallback() const { + std::lock_guard _lock{mWaitForBufferReleaseMutex}; + return mWaitForBufferReleaseCallback; +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) void BLASTBufferQueue::updateBufferReleaseProducer() { diff --git a/libs/gui/Flags.cpp b/libs/gui/Flags.cpp index 85ee2cddad..ee2802f706 100644 --- a/libs/gui/Flags.cpp +++ b/libs/gui/Flags.cpp @@ -29,6 +29,14 @@ sp<SurfaceType> surfaceToSurfaceType(const sp<Surface>& surface) { #endif } +ParcelableSurfaceType surfaceToParcelableSurfaceType(const sp<Surface>& surface) { +#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES + return view::Surface::fromSurface(surface); +#else + return surface->getIGraphicBufferProducer(); +#endif +} + sp<IGraphicBufferProducer> surfaceTypeToIGBP(const sp<SurfaceType>& surface) { #if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES return surface->getIGraphicBufferProducer(); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index be88b11b9c..cabde22c6d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -3293,10 +3293,17 @@ status_t SurfaceComposerClient::removeHdrLayerInfoListener( return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::setActivePictureListener( +status_t SurfaceComposerClient::addActivePictureListener( const sp<gui::IActivePictureListener>& listener) { binder::Status status = - ComposerServiceAIDL::getComposerService()->setActivePictureListener(listener); + ComposerServiceAIDL::getComposerService()->addActivePictureListener(listener); + return statusTFromBinderStatus(status); +} + +status_t SurfaceComposerClient::removeActivePictureListener( + const sp<gui::IActivePictureListener>& listener) { + binder::Status status = + ComposerServiceAIDL::getComposerService()->removeActivePictureListener(listener); return statusTFromBinderStatus(status); } diff --git a/libs/gui/aidl/android/gui/CaptureArgs.aidl b/libs/gui/aidl/android/gui/CaptureArgs.aidl index 4920344e0e..2bbed2b9d6 100644 --- a/libs/gui/aidl/android/gui/CaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl @@ -69,10 +69,5 @@ parcelable CaptureArgs { // exact colorspace is not an appropriate intermediate result. // Note that if the caller is requesting a specific dataspace, this hint does nothing. boolean hintForSeamlessTransition = false; - - // Allows the screenshot to attach a gainmap, which allows for a per-pixel - // transformation of the screenshot to another luminance range, typically - // mapping an SDR base image into HDR. - boolean attachGainmap = false; } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 8c19bbbba9..da47ee27ba 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -607,8 +607,14 @@ interface ISurfaceComposer { oneway void removeJankListener(int layerId, IJankListener listener, long afterVsync); /** - * Sets the listener used to monitor visible content that is being processed with picture + * Adds a listener used to monitor visible content that is being processed with picture * profiles. */ - oneway void setActivePictureListener(IActivePictureListener listener); + oneway void addActivePictureListener(IActivePictureListener listener); + + /** + * Removes a listener used to monitor visible content that is being processed with picture + * profiles. + */ + oneway void removeActivePictureListener(IActivePictureListener listener); } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 07558aa49d..1bc1dd0685 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -144,6 +144,12 @@ public: */ void setTransactionHangCallback(std::function<void(const std::string&)> callback); void setApplyToken(sp<IBinder>); + + void setWaitForBufferReleaseCallback(std::function<void()> callback) + EXCLUDES(mWaitForBufferReleaseMutex); + std::function<void()> getWaitForBufferReleaseCallback() const + EXCLUDES(mWaitForBufferReleaseMutex); + virtual ~BLASTBufferQueue(); void onFirstRef() override; @@ -186,6 +192,7 @@ private: sp<SurfaceControl> mSurfaceControl GUARDED_BY(mMutex); mutable std::mutex mMutex; + mutable std::mutex mWaitForBufferReleaseMutex; std::condition_variable mCallbackCV; // BufferQueue internally allows 1 more than @@ -324,6 +331,7 @@ private: std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex); + std::function<void()> mWaitForBufferReleaseCallback GUARDED_BY(mWaitForBufferReleaseMutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to the // client. diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h index 845bc54c71..446841bcd2 100644 --- a/libs/gui/include/gui/Flags.h +++ b/libs/gui/include/gui/Flags.h @@ -46,6 +46,7 @@ typedef android::sp<android::IGraphicBufferProducer> ParcelableSurfaceType; namespace flagtools { sp<SurfaceType> surfaceToSurfaceType(const sp<Surface>& surface); +ParcelableSurfaceType surfaceToParcelableSurfaceType(const sp<Surface>& surface); ParcelableSurfaceType toParcelableSurfaceType(const view::Surface& surface); sp<IGraphicBufferProducer> surfaceTypeToIGBP(const sp<SurfaceType>& surface); bool isSurfaceTypeValid(const sp<SurfaceType>& surface); diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0ce0c0a9c3..0f66c8b492 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -298,7 +298,9 @@ public: static status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener); - static status_t setActivePictureListener(const sp<gui::IActivePictureListener>& listener); + static status_t addActivePictureListener(const sp<gui::IActivePictureListener>& listener); + + static status_t removeActivePictureListener(const sp<gui::IActivePictureListener>& listener); /* * Sends a power boost to the composer. This function is asynchronous. diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index 45f41f1e8f..06f00a4d74 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -34,6 +34,8 @@ #include <binder/Parcel.h> #include <binder/ProcessState.h> +#include <gui/IConsumerListener.h> +#include <gui/IGraphicBufferConsumer.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> @@ -1225,9 +1227,17 @@ public: sp<IGraphicBufferConsumer> consumer; sp<IGraphicBufferProducer> producer; BufferQueue::createBufferQueue(&producer, &consumer); - consumer->setConsumerName(String8("Virtual disp consumer")); + consumer->setConsumerName(String8("Virtual disp consumer (MultiDisplayTests)")); consumer->setDefaultBufferSize(width, height); - mProducers.push_back(producer); + + class StubConsumerListener : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem&) override {} + virtual void onBuffersReleased() override {} + virtual void onSidebandStreamChanged() override {} + }; + + consumer->consumerConnect(sp<StubConsumerListener>::make(), true); + mBufferQueues.push_back({consumer, producer}); std::string name = "VirtualDisplay"; name += std::to_string(mVirtualDisplays.size()); @@ -1244,7 +1254,7 @@ public: } std::vector<sp<IBinder>> mVirtualDisplays; - std::vector<sp<IGraphicBufferProducer>> mProducers; + std::vector<std::tuple<sp<IGraphicBufferConsumer>, sp<IGraphicBufferProducer>>> mBufferQueues; }; TEST_F(MultiDisplayTests, drop_touch_if_layer_on_invalid_display) { diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 76362ff272..3185778acf 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1016,7 +1016,11 @@ public: return binder::Status::ok(); } - binder::Status setActivePictureListener(const sp<gui::IActivePictureListener>&) { + binder::Status addActivePictureListener(const sp<gui::IActivePictureListener>&) { + return binder::Status::ok(); + } + + binder::Status removeActivePictureListener(const sp<gui::IActivePictureListener>&) { return binder::Status::ok(); } diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index ca41346d46..3205c32f01 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -112,6 +112,10 @@ static_assert( static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) == AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM, "HAL and AHardwareBuffer pixel format don't match"); +static_assert( + static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::YCBCR_P210) == + AHARDWAREBUFFER_FORMAT_YCbCr_P210, + "HAL and AHardwareBuffer pixel format don't match"); static enum AHardwareBufferStatus filterStatus(status_t status) { switch (status) { @@ -300,8 +304,10 @@ int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, if (result == 0) { outPlanes->planeCount = 3; outPlanes->planes[0].data = yuvData.y; - // P010 is word-aligned 10-bit semiplaner, and YCbCr_422_I is a single interleaved plane + // P010 & P210 are word-aligned 10-bit semiplaner, and YCbCr_422_I is a single interleaved + // plane if (format == AHARDWAREBUFFER_FORMAT_YCbCr_P010 || + format == AHARDWAREBUFFER_FORMAT_YCbCr_P210 || format == AHARDWAREBUFFER_FORMAT_YCbCr_422_I) { outPlanes->planes[0].pixelStride = 2; } else { @@ -724,6 +730,7 @@ bool AHardwareBuffer_formatIsYuv(uint32_t format) { case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: case AHARDWAREBUFFER_FORMAT_YCbCr_P010: + case AHARDWAREBUFFER_FORMAT_YCbCr_P210: return true; default: return false; diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index 907590a236..873fc67c65 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -107,16 +107,15 @@ ftl::Future<FenceResult> RenderEngine::drawLayers(const DisplaySettings& display return resultFuture; } -ftl::Future<FenceResult> RenderEngine::drawGainmap( - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, +ftl::Future<FenceResult> RenderEngine::tonemapAndDrawGainmap( const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); std::future<FenceResult> resultFuture = resultPromise->get_future(); updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); - drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, - std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + tonemapAndDrawGainmapInternal(std::move(resultPromise), hdr, std::move(hdrFence), hdrSdrRatio, + dataspace, sdr, gainmap); return resultFuture; } diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 95c4d033e2..c2dd4ae97e 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -217,12 +217,17 @@ public: const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence); - virtual ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap); + // Tonemaps an HDR input image and draws an SDR rendition, plus a gainmap + // describing how to recover the HDR image. + // + // The HDR input image is ALWAYS encoded with an sRGB transfer function and + // is a floating point format. Accordingly, the hdrSdrRatio describes the + // max luminance in the HDR input image above SDR, and the dataspace + // describes the input primaries. + virtual ftl::Future<FenceResult> tonemapAndDrawGainmap( + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap); // Clean-up method that should be called on the main thread after the // drawFence returned by drawLayers fires. This method will free up @@ -310,11 +315,10 @@ protected: const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) = 0; - virtual void drawGainmapInternal( + virtual void tonemapAndDrawGainmapInternal( const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) = 0; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index fb8331d870..c42e4034e0 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -46,17 +46,16 @@ public: ftl::Future<FenceResult>(const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, base::unique_fd&&)); - MOCK_METHOD7(drawGainmap, + MOCK_METHOD6(tonemapAndDrawGainmap, ftl::Future<FenceResult>(const std::shared_ptr<ExternalTexture>&, - base::borrowed_fd&&, - const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, float, ui::Dataspace, + const std::shared_ptr<ExternalTexture>&, const std::shared_ptr<ExternalTexture>&)); - MOCK_METHOD8(drawGainmapInternal, + MOCK_METHOD7(tonemapAndDrawGainmapInternal, void(const std::shared_ptr<std::promise<FenceResult>>&&, - const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, float, - ui::Dataspace, const std::shared_ptr<ExternalTexture>&)); + ui::Dataspace, const std::shared_ptr<ExternalTexture>&, + const std::shared_ptr<ExternalTexture>&)); MOCK_METHOD5(drawLayersInternal, void(const std::shared_ptr<std::promise<FenceResult>>&&, const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index b3284e48c5..7e8ccef18e 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -567,9 +567,7 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( if (usingLocalTonemap) { const float inputRatio = hdrType == HdrRenderType::GENERIC_HDR ? 1.0f : parameters.layerDimmingRatio; - static MouriMap kMapper; - shader = kMapper.mouriMap(getActiveContext(), shader, inputRatio, - parameters.display.targetHdrSdrRatio); + shader = localTonemap(shader, inputRatio, parameters.display.targetHdrSdrRatio); } // disable tonemapping if we already locally tonemapped @@ -610,6 +608,12 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( return shader; } +sk_sp<SkShader> SkiaRenderEngine::localTonemap(sk_sp<SkShader> shader, float inputMultiplier, + float targetHdrSdrRatio) { + static MouriMap kMapper; + return kMapper.mouriMap(getActiveContext(), shader, inputMultiplier, targetHdrSdrRatio); +} + void SkiaRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) { if (CC_UNLIKELY(mCapture->isCaptureRunning())) { // Record display settings when capture is running. @@ -1009,7 +1013,7 @@ void SkiaRenderEngine::drawLayersInternal( const auto& item = layer.source.buffer; auto imageTextureRef = getOrCreateBackendTexture(item.buffer->getBuffer(), false); - // if the layer's buffer has a fence, then we must must respect the fence prior to using + // if the layer's buffer has a fence, then we must respect the fence prior to using // the buffer. if (layer.source.buffer.fence != nullptr) { waitFence(context, layer.source.buffer.fence->get()); @@ -1212,44 +1216,58 @@ void SkiaRenderEngine::drawLayersInternal( resultPromise->set_value(std::move(drawFence)); } -void SkiaRenderEngine::drawGainmapInternal( +void SkiaRenderEngine::tonemapAndDrawGainmapInternal( const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { std::lock_guard<std::mutex> lock(mRenderingMutex); auto context = getActiveContext(); - auto surfaceTextureRef = getOrCreateBackendTexture(gainmap->getBuffer(), true); - sk_sp<SkSurface> dstSurface = - surfaceTextureRef->getOrCreateSurface(ui::Dataspace::V0_SRGB_LINEAR); - - waitFence(context, sdrFence); - const auto sdrTextureRef = getOrCreateBackendTexture(sdr->getBuffer(), false); - const auto sdrImage = sdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); - const auto sdrShader = - sdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, - SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), - nullptr); + auto gainmapTextureRef = getOrCreateBackendTexture(gainmap->getBuffer(), true); + sk_sp<SkSurface> gainmapSurface = + gainmapTextureRef->getOrCreateSurface(ui::Dataspace::V0_SRGB_LINEAR); + + auto sdrTextureRef = getOrCreateBackendTexture(sdr->getBuffer(), true); + sk_sp<SkSurface> sdrSurface = sdrTextureRef->getOrCreateSurface(dataspace); + waitFence(context, hdrFence); const auto hdrTextureRef = getOrCreateBackendTexture(hdr->getBuffer(), false); const auto hdrImage = hdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); const auto hdrShader = hdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, - SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), + SkSamplingOptions({SkFilterMode::kNearest, SkMipmapMode::kNone}), nullptr); + const auto tonemappedShader = localTonemap(hdrShader, 1.0f, 1.0f); + static GainmapFactory kGainmapFactory; - const auto gainmapShader = kGainmapFactory.createSkShader(sdrShader, hdrShader, hdrSdrRatio); + const auto gainmapShader = + kGainmapFactory.createSkShader(tonemappedShader, hdrShader, hdrSdrRatio); - const auto canvas = dstSurface->getCanvas(); - SkPaint paint; - paint.setShader(gainmapShader); - paint.setBlendMode(SkBlendMode::kSrc); - canvas->drawPaint(paint); + sp<Fence> drawFence; - auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); - trace(drawFence); + { + const auto canvas = sdrSurface->getCanvas(); + SkPaint paint; + paint.setShader(tonemappedShader); + paint.setBlendMode(SkBlendMode::kSrc); + canvas->drawPaint(paint); + + drawFence = sp<Fence>::make(flushAndSubmit(context, sdrSurface)); + trace(drawFence); + } + + { + const auto canvas = gainmapSurface->getCanvas(); + SkPaint paint; + paint.setShader(gainmapShader); + paint.setBlendMode(SkBlendMode::kSrc); + canvas->drawPaint(paint); + + auto gmFence = sp<Fence>::make(flushAndSubmit(context, gainmapSurface)); + trace(gmFence); + drawFence = Fence::merge("gm-ss", drawFence, gmFence); + } resultPromise->set_value(std::move(drawFence)); } diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 7be4c253e7..92b7af985c 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -143,13 +143,11 @@ private: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override final; - void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap) override final; + void tonemapAndDrawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap) override final; void dump(std::string& result) override final; @@ -168,6 +166,8 @@ private: }; sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&); + sk_sp<SkShader> localTonemap(sk_sp<SkShader>, float inputMultiplier, float targetHdrSdrRatio); + const PixelFormat mDefaultPixelFormat; // Identifier used for various mappings of layers to various diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp index 5e9dfbba3e..8fc3286c07 100644 --- a/libs/renderengine/skia/filters/LutShader.cpp +++ b/libs/renderengine/skia/filters/LutShader.cpp @@ -39,10 +39,13 @@ static const SkString kShader = SkString(R"( uniform int key; uniform int dimension; uniform vec3 luminanceCoefficients; // for CIE_Y + // for hlg/pq transfer function, we need normalize it to [0.0, 1.0] + // we use `normalizeScalar` to do so + uniform float normalizeScalar; vec4 main(vec2 xy) { float4 rgba = image.eval(xy); - float3 linear = toLinearSrgb(rgba.rgb); + float3 linear = toLinearSrgb(rgba.rgb) * normalizeScalar; if (dimension == 1) { // RGB if (key == 0) { @@ -52,19 +55,19 @@ static const SkString kShader = SkString(R"( float gainR = lut.eval(vec2(indexR, 0.0) + 0.5).r; float gainG = lut.eval(vec2(indexG, 0.0) + 0.5).r; float gainB = lut.eval(vec2(indexB, 0.0) + 0.5).r; - return float4(linear.r * gainR, linear.g * gainG, linear.b * gainB, rgba.a); + linear = float3(linear.r * gainR, linear.g * gainG, linear.b * gainB); // MAX_RGB } else if (key == 1) { float maxRGB = max(linear.r, max(linear.g, linear.b)); float index = maxRGB * float(size - 1); float gain = lut.eval(vec2(index, 0.0) + 0.5).r; - return float4(linear * gain, rgba.a); + linear = linear * gain; // CIE_Y } else if (key == 2) { float y = dot(linear, luminanceCoefficients) / 3.0; float index = y * float(size - 1); float gain = lut.eval(vec2(index, 0.0) + 0.5).r; - return float4(linear * gain, rgba.a); + linear = linear * gain; } } else if (dimension == 3) { if (key == 0) { @@ -110,12 +113,10 @@ static const SkString kShader = SkString(R"( float3 c0 = mix(c00, c10, linear.g); float3 c1 = mix(c01, c11, linear.g); - float3 val = mix(c0, c1, linear.b); - - return float4(val, rgba.a); + linear = mix(c0, c1, linear.b); } } - return rgba; + return float4(linear, rgba.a); })"); // same as shader::toColorSpace function @@ -197,9 +198,22 @@ sk_sp<SkShader> LutShader::generateLutShader(sk_sp<SkShader> input, ? SkSamplingOptions(SkFilterMode::kLinear) : SkSamplingOptions()); + float normalizeScalar = 1.0; + switch (srcDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_HLG: + normalizeScalar = 0.203; + break; + case HAL_DATASPACE_TRANSFER_ST2084: + normalizeScalar = 0.0203; + break; + default: + normalizeScalar = 1.0; + } const int uSize = static_cast<int>(size); const int uKey = static_cast<int>(samplingKey); const int uDimension = static_cast<int>(dimension); + const float uNormalizeScalar = static_cast<float>(normalizeScalar); + if (static_cast<LutProperties::SamplingKey>(samplingKey) == LutProperties::SamplingKey::CIE_Y) { // Use predefined colorspaces of input dataspace so that we can get D65 illuminant mat3 toXYZMatrix(toColorSpace(srcDataspace).getRGBtoXYZ()); @@ -211,6 +225,7 @@ sk_sp<SkShader> LutShader::generateLutShader(sk_sp<SkShader> input, mBuilder->uniform("size") = uSize; mBuilder->uniform("key") = uKey; mBuilder->uniform("dimension") = uDimension; + mBuilder->uniform("normalizeScalar") = uNormalizeScalar; return mBuilder->makeShader(); } diff --git a/libs/renderengine/skia/filters/MouriMap.cpp b/libs/renderengine/skia/filters/MouriMap.cpp index b099bcf3d7..aa12cef615 100644 --- a/libs/renderengine/skia/filters/MouriMap.cpp +++ b/libs/renderengine/skia/filters/MouriMap.cpp @@ -30,12 +30,12 @@ sk_sp<SkRuntimeEffect> makeEffect(const SkString& sksl) { } const SkString kCrosstalkAndChunk16x16(R"( uniform shader bitmap; - uniform float hdrSdrRatio; + uniform float inputMultiplier; vec4 main(vec2 xy) { float maximum = 0.0; for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { - float3 linear = toLinearSrgb(bitmap.eval((xy - 0.5) * 16 + 0.5 + vec2(x, y)).rgb) * hdrSdrRatio; + float3 linear = toLinearSrgb(bitmap.eval((xy - 0.5) * 16 + 0.5 + vec2(x, y)).rgb) * inputMultiplier; float maxRGB = max(linear.r, max(linear.g, linear.b)); maximum = max(maximum, log2(max(maxRGB, 1.0))); } @@ -77,12 +77,12 @@ const SkString kTonemap(R"( uniform shader image; uniform shader lux; uniform float scaleFactor; - uniform float hdrSdrRatio; + uniform float inputMultiplier; uniform float targetHdrSdrRatio; vec4 main(vec2 xy) { float localMax = lux.eval(xy * scaleFactor).r; float4 rgba = image.eval(xy); - float3 linear = toLinearSrgb(rgba.rgb) * hdrSdrRatio; + float3 linear = toLinearSrgb(rgba.rgb) * inputMultiplier; if (localMax <= targetHdrSdrRatio) { return float4(fromLinearSrgb(linear), rgba.a); @@ -116,19 +116,19 @@ MouriMap::MouriMap() mTonemap(makeEffect(kTonemap)) {} sk_sp<SkShader> MouriMap::mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, - float hdrSdrRatio, float targetHdrSdrRatio) { - auto downchunked = downchunk(context, input, hdrSdrRatio); + float inputMultiplier, float targetHdrSdrRatio) { + auto downchunked = downchunk(context, input, inputMultiplier); auto localLux = blur(context, downchunked.get()); - return tonemap(input, localLux.get(), hdrSdrRatio, targetHdrSdrRatio); + return tonemap(input, localLux.get(), inputMultiplier, targetHdrSdrRatio); } sk_sp<SkImage> MouriMap::downchunk(SkiaGpuContext* context, sk_sp<SkShader> input, - float hdrSdrRatio) const { + float inputMultiplier) const { SkMatrix matrix; SkImage* image = input->isAImage(&matrix, (SkTileMode*)nullptr); SkRuntimeShaderBuilder crosstalkAndChunk16x16Builder(mCrosstalkAndChunk16x16); crosstalkAndChunk16x16Builder.child("bitmap") = input; - crosstalkAndChunk16x16Builder.uniform("hdrSdrRatio") = hdrSdrRatio; + crosstalkAndChunk16x16Builder.uniform("inputMultiplier") = inputMultiplier; // TODO: fp16 might be overkill. Most practical surfaces use 8-bit RGB for HDR UI and 10-bit YUV // for HDR video. These downsample operations compute log2(max(linear RGB, 1.0)). So we don't // care about LDR precision since they all resolve to LDR-max. For appropriately mastered HDR @@ -168,7 +168,7 @@ sk_sp<SkImage> MouriMap::blur(SkiaGpuContext* context, SkImage* input) const { LOG_ALWAYS_FATAL_IF(!blurSurface, "%s: Failed to create surface!", __func__); return makeImage(blurSurface.get(), blurBuilder); } -sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio, +sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, float inputMultiplier, float targetHdrSdrRatio) const { static constexpr float kScaleFactor = 1.0f / 128.0f; SkRuntimeShaderBuilder tonemapBuilder(mTonemap); @@ -177,7 +177,7 @@ sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, floa localLux->makeRawShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone)); tonemapBuilder.uniform("scaleFactor") = kScaleFactor; - tonemapBuilder.uniform("hdrSdrRatio") = hdrSdrRatio; + tonemapBuilder.uniform("inputMultiplier") = inputMultiplier; tonemapBuilder.uniform("targetHdrSdrRatio") = targetHdrSdrRatio; return tonemapBuilder.makeShader(); } diff --git a/libs/renderengine/skia/filters/MouriMap.h b/libs/renderengine/skia/filters/MouriMap.h index 9ba2b6ff9d..f4bfa1549e 100644 --- a/libs/renderengine/skia/filters/MouriMap.h +++ b/libs/renderengine/skia/filters/MouriMap.h @@ -62,10 +62,13 @@ class MouriMap { public: MouriMap(); // Apply the MouriMap tonemmaping operator to the input. - // The HDR/SDR ratio describes the luminace range of the input. 1.0 means SDR. Anything larger - // then 1.0 means that there is headroom above the SDR region. - // Similarly, the target HDR/SDR ratio describes the luminance range of the output. - sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float inputHdrSdrRatio, + // The inputMultiplier informs how to interpret the luminance encoding of the input. + // For a fixed point input, this is necessary to interpret what "1.0" means for the input + // pixels, so that the luminance can be scaled appropriately, such that the operator can + // transform SDR values to be within 1.0. For a floating point input, "1.0" always means SDR, + // so the caller must pass 1.0. + // The target HDR/SDR ratio describes the luminance range of the output. + sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float inputMultiplier, float targetHdrSdrRatio); private: diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index c187f93089..ea5605d4bd 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -249,11 +249,10 @@ void RenderEngineThreaded::drawLayersInternal( return; } -void RenderEngineThreaded::drawGainmapInternal( +void RenderEngineThreaded::tonemapAndDrawGainmapInternal( const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { resultPromise->set_value(Fence::NO_FENCE); return; @@ -281,10 +280,9 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( return resultFuture; } -ftl::Future<FenceResult> RenderEngineThreaded::drawGainmap( - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, +ftl::Future<FenceResult> RenderEngineThreaded::tonemapAndDrawGainmap( const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { SFTRACE_CALL(); const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); @@ -292,13 +290,14 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawGainmap( { std::lock_guard lock(mThreadMutex); mNeedsPostRenderCleanup = true; - mFunctionCalls.push([resultPromise, sdr, sdrFence = std::move(sdrFence), hdr, - hdrFence = std::move(hdrFence), hdrSdrRatio, dataspace, + mFunctionCalls.push([resultPromise, hdr, hdrFence = std::move(hdrFence), hdrSdrRatio, + dataspace, sdr, gainmap](renderengine::RenderEngine& instance) mutable { - SFTRACE_NAME("REThreaded::drawGainmap"); - instance.updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); - instance.drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, - std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + SFTRACE_NAME("REThreaded::tonemapAndDrawGainmap"); + instance.updateProtectedContext({}, {hdr.get(), sdr.get(), gainmap.get()}); + instance.tonemapAndDrawGainmapInternal(std::move(resultPromise), hdr, + std::move(hdrFence), hdrSdrRatio, dataspace, sdr, + gainmap); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index cb6e924d81..8554b55030 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -55,12 +55,10 @@ public: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; - ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap) override; + ftl::Future<FenceResult> tonemapAndDrawGainmap( + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap) override; int getContextPriority() override; bool supportsBackgroundBlur() override; @@ -77,13 +75,11 @@ protected: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; - void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap) override; + void tonemapAndDrawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap) override; private: void threadMain(CreateInstanceFactory factory); diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp index 8d6f74b605..c9f0761a01 100644 --- a/libs/ui/DisplayIdentification.cpp +++ b/libs/ui/DisplayIdentification.cpp @@ -417,6 +417,7 @@ std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData( return DisplayIdentificationInfo{ .id = displayId, .name = std::string(edid->displayName), + .port = port, .deviceProductInfo = buildDeviceProductInfo(*edid), .preferredDetailedTimingDescriptor = edid->preferredDetailedTimingDescriptor, }; diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index b0c6e44b2b..18c9a6bc48 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -596,6 +596,8 @@ status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& width = height = stride = format = usage_deprecated = 0; layerCount = 0; usage = 0; + native_handle_close(handle); + native_handle_delete(const_cast<native_handle_t*>(handle)); handle = nullptr; ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err); return err; diff --git a/libs/ui/include/ui/DisplayIdentification.h b/libs/ui/include/ui/DisplayIdentification.h index cf67d7bf93..cdac2698dd 100644 --- a/libs/ui/include/ui/DisplayIdentification.h +++ b/libs/ui/include/ui/DisplayIdentification.h @@ -42,6 +42,7 @@ struct DetailedTimingDescriptor { struct DisplayIdentificationInfo { PhysicalDisplayId id; std::string name; + uint8_t port; std::optional<DeviceProductInfo> deviceProductInfo; std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor; }; diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h index e87931efed..7c17763860 100644 --- a/libs/ui/include/ui/PublicFormat.h +++ b/libs/ui/include/ui/PublicFormat.h @@ -60,6 +60,7 @@ enum class PublicFormat { JPEG_R = 0x1005, HEIC = 0x48454946, HEIC_ULTRAHDR = 0x1006, + YCBCR_P210 = 0x3c, }; /* Convert from android.graphics.ImageFormat/PixelFormat enums to graphics.h HAL diff --git a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java index 5c12323633..fc0aef4964 100644 --- a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java +++ b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java @@ -39,29 +39,9 @@ import java.util.stream.Collectors; @RunWith(DeviceJUnit4ClassRunner.class) public class GpuWorkTracepointTest extends BaseHostJUnit4Test { - private static final String CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH = - "/sys/kernel/tracing/events/power/cpu_frequency/format"; private static final String GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH = "/sys/kernel/tracing/events/power/gpu_work_period/format"; - @Test - public void testReadTracingEvents() throws Exception { - // Test |testGpuWorkPeriodTracepointFormat| is dependent on whether certain tracepoint - // paths exist. This means the test will vacuously pass if the tracepoint file system is - // inaccessible. Thus, as a basic check, we make sure the CPU frequency tracepoint format - // is accessible. If not, something is probably fundamentally broken about the tracing - // file system. - CommandResult commandResult = getDevice().executeShellV2Command( - String.format("cat %s", CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH)); - - assertEquals(String.format( - "Failed to read \"%s\". This probably means that the tracing file system " - + "is fundamentally broken in some way, possibly due to bad " - + "permissions.", - CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH), - commandResult.getStatus(), CommandStatus.SUCCESS); - } - @VsrTest(requirements={"VSR-3.3-004"}) @RequiresDevice @Test diff --git a/services/surfaceflinger/ActivePictureUpdater.cpp b/services/surfaceflinger/ActivePictureTracker.cpp index 210e948a49..4e6fa66ed8 100644 --- a/services/surfaceflinger/ActivePictureUpdater.cpp +++ b/services/surfaceflinger/ActivePictureTracker.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "ActivePictureUpdater.h" +#include "ActivePictureTracker.h" #include <algorithm> @@ -23,7 +23,10 @@ namespace android { -void ActivePictureUpdater::onLayerComposed(const Layer& layer, const LayerFE& layerFE, +using gui::ActivePicture; +using gui::IActivePictureListener; + +void ActivePictureTracker::onLayerComposed(const Layer& layer, const LayerFE& layerFE, const CompositionResult& result) { if (result.wasPictureProfileCommitted) { gui::ActivePicture picture; @@ -39,10 +42,47 @@ void ActivePictureUpdater::onLayerComposed(const Layer& layer, const LayerFE& la } } -bool ActivePictureUpdater::updateAndHasChanged() { +void ActivePictureTracker::updateAndNotifyListeners(const Listeners& listenersToAdd, + const Listeners& listenersToRemove) { + Listeners newListeners = updateListeners(listenersToAdd, listenersToRemove); + if (updateAndHasChanged()) { + for (auto listener : mListeners) { + listener->onActivePicturesChanged(getActivePictures()); + } + } else { + for (auto listener : newListeners) { + listener->onActivePicturesChanged(getActivePictures()); + } + } +} + +ActivePictureTracker::Listeners ActivePictureTracker::updateListeners( + const Listeners& listenersToAdd, const Listeners& listenersToRemove) { + Listeners newListeners; + for (auto listener : listenersToRemove) { + std::erase_if(mListeners, [listener](const sp<IActivePictureListener>& otherListener) { + return IInterface::asBinder(listener) == IInterface::asBinder(otherListener); + }); + } + for (auto listener : listenersToAdd) { + if (std::find_if(mListeners.begin(), mListeners.end(), + [listener](const sp<IActivePictureListener>& otherListener) { + return IInterface::asBinder(listener) == + IInterface::asBinder(otherListener); + }) == mListeners.end()) { + newListeners.push_back(listener); + } + } + for (auto listener : newListeners) { + mListeners.push_back(listener); + } + return newListeners; +} + +bool ActivePictureTracker::updateAndHasChanged() { bool hasChanged = true; if (mNewActivePictures.size() == mOldActivePictures.size()) { - auto compare = [](const gui::ActivePicture& lhs, const gui::ActivePicture& rhs) -> int { + auto compare = [](const ActivePicture& lhs, const ActivePicture& rhs) -> int { if (lhs.layerId == rhs.layerId) { return lhs.pictureProfileId < rhs.pictureProfileId; } @@ -59,7 +99,7 @@ bool ActivePictureUpdater::updateAndHasChanged() { return hasChanged; } -const std::vector<gui::ActivePicture>& ActivePictureUpdater::getActivePictures() const { +const std::vector<ActivePicture>& ActivePictureTracker::getActivePictures() const { return mOldActivePictures; } diff --git a/services/surfaceflinger/ActivePictureUpdater.h b/services/surfaceflinger/ActivePictureTracker.h index 20779bb0ff..cb319a58be 100644 --- a/services/surfaceflinger/ActivePictureUpdater.h +++ b/services/surfaceflinger/ActivePictureTracker.h @@ -19,6 +19,7 @@ #include <vector> #include <android/gui/ActivePicture.h> +#include <android/gui/IActivePictureListener.h> namespace android { @@ -27,21 +28,28 @@ class LayerFE; struct CompositionResult; // Keeps track of active pictures - layers that are undergoing picture processing. -class ActivePictureUpdater { +class ActivePictureTracker { public: + typedef std::vector<sp<gui::IActivePictureListener>> Listeners; + // Called for each visible layer when SurfaceFlinger finishes composing. void onLayerComposed(const Layer& layer, const LayerFE& layerFE, const CompositionResult& result); // Update internals and return whether the set of active pictures have changed. - bool updateAndHasChanged(); + void updateAndNotifyListeners(const Listeners& activePictureListenersToAdd, + const Listeners& activePictureListenersToRemove); // The current set of active pictures. const std::vector<gui::ActivePicture>& getActivePictures() const; private: + Listeners updateListeners(const Listeners& listenersToAdd, const Listeners& listenersToRemove); + bool updateAndHasChanged(); + std::vector<gui::ActivePicture> mOldActivePictures; std::vector<gui::ActivePicture> mNewActivePictures; + Listeners mListeners; }; } // namespace android diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 3f3d2c6cc6..71c779e366 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -42,12 +42,12 @@ cc_defaults { name: "libsurfaceflinger_defaults", defaults: [ "android.hardware.graphics.composer3-ndk_shared", - "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "libsurfaceflinger_common_deps", "surfaceflinger_defaults", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", @@ -79,7 +79,6 @@ cc_defaults { "libhidlbase", "liblog", "libnativewindow", - "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", "libstatslog_surfaceflinger", @@ -199,7 +198,7 @@ filegroup { name: "libsurfaceflinger_sources", srcs: [ ":libsurfaceflinger_backend_sources", - "ActivePictureUpdater.cpp", + "ActivePictureTracker.cpp", "BackgroundExecutor.cpp", "Client.cpp", "ClientCache.cpp", diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 82eafd4fa8..2d0f874ad0 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -13,11 +13,11 @@ cc_defaults { defaults: [ "aconfig_lib_cc_static_link.defaults", "android.hardware.graphics.composer3-ndk_shared", - "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "surfaceflinger_defaults", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], cflags: [ "-DLOG_TAG=\"CompositionEngine\"", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index 2e7a7d9c5a..c1b864df02 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -118,7 +118,8 @@ public: // isPeekingThrough specifies whether this layer will be shown through a // hole punch in a layer above it. virtual void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, - bool zIsOverridden, bool isPeekingThrough) = 0; + bool zIsOverridden, bool isPeekingThrough, + bool isLutSupported) = 0; // Updates the cursor position with the HWC virtual void writeCursorPositionToHWC() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 712b55123f..0063eee0e1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -58,7 +58,7 @@ public: const std::optional<std::vector<std::optional<LutProperties>>> properties = std::nullopt) override; void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, - bool isPeekingThrough) override; + bool isPeekingThrough, bool hasLutsProperties) override; void writeCursorPositionToHWC() const override; HWC2::Layer* getHwcLayer() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 9333ebb8cd..09c47f0224 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -47,7 +47,7 @@ public: (bool, bool, ui::Transform::RotationFlags, (const std::optional<std::vector<std::optional< aidl::android::hardware::graphics::composer3::LutProperties>>>))); - MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool)); + MOCK_METHOD(void, writeStateToHWC, (bool, bool, uint32_t, bool, bool, bool)); MOCK_CONST_METHOD0(writeCursorPositionToHWC, void()); MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index bee03e6310..734d76404e 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -909,6 +909,9 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr applyPictureProfile(); + auto* properties = getOverlaySupport(); + bool hasLutsProperties = properties && properties->lutProperties.has_value(); + compositionengine::OutputLayer* peekThroughLayer = nullptr; sp<GraphicBuffer> previousOverride = nullptr; bool includeGeometry = refreshArgs.updatingGeometryThisFrame; @@ -940,7 +943,7 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr includeGeometry = true; constexpr bool isPeekingThrough = true; peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ, - isPeekingThrough); + isPeekingThrough, hasLutsProperties); outputLayerHash ^= android::hashCombine( reinterpret_cast<uint64_t>(&peekThroughLayer->getLayerFE()), z, includeGeometry, overrideZ, isPeekingThrough, @@ -952,7 +955,8 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr } constexpr bool isPeekingThrough = false; - layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough); + layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough, + hasLutsProperties); if (!skipLayer) { outputLayerHash ^= android::hashCombine( reinterpret_cast<uint64_t>(&layer->getLayerFE()), diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index a040c88e78..96b86d5a31 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -449,7 +449,8 @@ void OutputLayer::commitPictureProfileToCompositionState() { } void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, - bool zIsOverridden, bool isPeekingThrough) { + bool zIsOverridden, bool isPeekingThrough, + bool hasLutsProperties) { const auto& state = getState(); // Skip doing this if there is no HWC interface if (!state.hwc) { @@ -491,8 +492,9 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough, skipLayer); - - writeLutToHWC(hwcLayer.get(), *outputIndependentState); + if (hasLutsProperties) { + writeLutToHWC(hwcLayer.get(), *outputIndependentState); + } if (requestedCompositionType == Composition::SOLID_COLOR) { writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); @@ -589,29 +591,30 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( void OutputLayer::writeLutToHWC(HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) { - if (!outputIndependentState.luts) { - return; - } - auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); - auto lutOffsets = outputIndependentState.luts->offsets; - auto& lutProperties = outputIndependentState.luts->lutProperties; + Luts luts; + // if outputIndependentState.luts is nullptr, it means we want to clear the LUTs + // and we pass an empty Luts object to the HWC. + if (outputIndependentState.luts) { + auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); + auto lutOffsets = outputIndependentState.luts->offsets; + auto& lutProperties = outputIndependentState.luts->lutProperties; + + std::vector<LutProperties> aidlProperties; + aidlProperties.reserve(lutProperties.size()); + for (size_t i = 0; i < lutOffsets.size(); i++) { + aidlProperties.emplace_back( + LutProperties{.dimension = static_cast<LutProperties::Dimension>( + lutProperties[i].dimension), + .size = lutProperties[i].size, + .samplingKeys = {static_cast<LutProperties::SamplingKey>( + lutProperties[i].samplingKey)}}); + } - std::vector<LutProperties> aidlProperties; - aidlProperties.reserve(lutProperties.size()); - for (size_t i = 0; i < lutOffsets.size(); i++) { - LutProperties properties; - properties.dimension = static_cast<LutProperties::Dimension>(lutProperties[i].dimension); - properties.size = lutProperties[i].size; - properties.samplingKeys = { - static_cast<LutProperties::SamplingKey>(lutProperties[i].samplingKey)}; - aidlProperties.emplace_back(properties); + luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); + luts.offsets = lutOffsets; + luts.lutProperties = std::move(aidlProperties); } - Luts luts; - luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); - luts.offsets = lutOffsets; - luts.lutProperties = std::move(aidlProperties); - switch (auto error = hwcLayer->setLuts(luts)) { case hal::Error::NONE: break; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index dbffe80a3a..ca262ee16a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -541,6 +541,9 @@ struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLaye MOCK_CONST_METHOD1(calculateOutputSourceCrop, FloatRect(uint32_t)); MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect()); MOCK_CONST_METHOD1(calculateOutputRelativeBufferTransform, uint32_t(uint32_t)); + MOCK_METHOD(void, updateLuts, + (const LayerFECompositionState&, + const std::optional<std::vector<std::optional<LutProperties>>>&)); // compositionengine::OutputLayer overrides const compositionengine::Output& getOutput() const override { return mOutput; } @@ -985,21 +988,24 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) { EXPECT_CALL(mLayerFE, getCompositionState()).WillOnce(Return(nullptr)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) { mOutputLayer.editState().hwc.reset(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCLayer) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc(nullptr); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { @@ -1010,7 +1016,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { EXPECT_CALL(mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) { @@ -1041,7 +1048,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { expectSetColorCall(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { @@ -1052,7 +1060,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { expectSetCompositionTypeCall(Composition::SIDEBAND); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { @@ -1063,7 +1072,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { expectSetCompositionTypeCall(Composition::CURSOR); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { @@ -1074,7 +1084,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { @@ -1087,7 +1098,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { expectNoSetCompositionTypeCall(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) { @@ -1098,7 +1110,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransf expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) { @@ -1111,7 +1124,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { @@ -1125,7 +1139,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) { @@ -1137,7 +1152,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPres expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { @@ -1152,7 +1168,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSendBuffer) { @@ -1167,7 +1184,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSe expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { @@ -1182,7 +1200,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresent) { @@ -1197,7 +1216,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresen expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage) { @@ -1211,7 +1231,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompositionInfo) { @@ -1227,7 +1248,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompos expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedClientCompositionInfo) { @@ -1244,7 +1266,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedClientCompos expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, peekThroughChangesBlendMode) { @@ -1258,7 +1281,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, peekThroughChangesBlendMode) { expectPerFrameCommonCalls(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, isPeekingThroughSetsOverride) { @@ -1266,7 +1290,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, isPeekingThroughSetsOverride) { expectPerFrameCommonCalls(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ true); + /*zIsOverridden*/ false, /*isPeekingThrough*/ true, + /*hasLutsProperties*/ false); EXPECT_TRUE(mOutputLayer.getState().hwc->stateOverridden); } @@ -1276,7 +1301,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, zIsOverriddenSetsOverride) { mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ true, /*isPeekingThrough*/ - false); + false, /*hasLutsProperties*/ false); EXPECT_TRUE(mOutputLayer.getState().hwc->stateOverridden); } @@ -1288,7 +1313,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersForceClientComposition) { mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ - false); + false, /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceComposition) { @@ -1301,7 +1326,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceC mLayerFEState.compositionType = Composition::DEVICE; mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ - true); + true, /*hasLutsProperties*/ false); EXPECT_EQ(Composition::DEVICE, mOutputLayer.getState().hwc->hwcCompositionType); } @@ -1318,7 +1343,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, setBlockingRegion) { mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ - false); + false, /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, setCompositionTypeRefreshRateIndicator) { @@ -1330,7 +1355,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, setCompositionTypeRefreshRateIndicator) { expectSetCompositionTypeCall(Composition::REFRESH_RATE_INDICATOR); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, setsPictureProfileWhenCommitted) { @@ -1349,7 +1375,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, setsPictureProfileWhenCommitted) { mOutputLayer.commitPictureProfileToCompositionState(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommitted) { @@ -1367,7 +1394,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommitted) EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(_)).Times(0); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommittedLater) { @@ -1386,7 +1414,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommittedL mOutputLayer.commitPictureProfileToCompositionState(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); expectGeometryCommonCalls(); expectPerFrameCommonCalls(); @@ -1395,7 +1424,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommittedL EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(PictureProfileHandle(1))).Times(0); // No committing of picture profile before writing the state mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } /* @@ -1441,21 +1471,24 @@ TEST_F(OutputLayerUncacheBufferTest, canUncacheAndReuseSlot) { mLayerFEState.buffer = kBuffer1; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 0, kBuffer1, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer2 is stored in slot 1 mLayerFEState.buffer = kBuffer2; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, kBuffer2, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer3 is stored in slot 2 mLayerFEState.buffer = kBuffer3; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 2, kBuffer3, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer2 becomes the active buffer again (with a nullptr) and reuses slot 1 @@ -1463,7 +1496,8 @@ TEST_F(OutputLayerUncacheBufferTest, canUncacheAndReuseSlot) { sp<GraphicBuffer> nullBuffer = nullptr; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, nullBuffer, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer slots are cleared @@ -1481,7 +1515,8 @@ TEST_F(OutputLayerUncacheBufferTest, canUncacheAndReuseSlot) { mLayerFEState.buffer = kBuffer1; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, kBuffer1, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index dd2ca7cb38..09ad9fa497 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -813,19 +813,22 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer1); @@ -852,17 +855,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer1); @@ -888,17 +894,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer1); @@ -932,7 +941,8 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { uint32_t z = 0; EXPECT_CALL(*layer0.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer0.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); // After calling planComposition (which clears overrideInfo), this test sets @@ -942,15 +952,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ true, /*isPeekingThrough*/ - true)); + true, /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ true, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ true, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, z++, - /*zIsOverridden*/ true, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ true, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer0); @@ -4962,12 +4974,14 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) { EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); layer2.layerFEState.backgroundBlurRadius = 10; @@ -4996,17 +5010,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); layer2.layerFEState.backgroundBlurRadius = 10; @@ -5036,17 +5053,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); BlurRegion region; @@ -5101,13 +5121,13 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsDisplayProfileBasedOnLay // Because StrictMock EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer1.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _, _)); // No layer picture profiles should be committed EXPECT_CALL(*layer1.outputLayer, commitPictureProfileToCompositionState).Times(0); @@ -5164,13 +5184,13 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsLayerProfileBasedOnLayer // Because StrictMock EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer1.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _, _)); // The two highest priority layers should have their picture profiles committed EXPECT_CALL(*layer1.outputLayer, commitPictureProfileToCompositionState).Times(0); diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp index 0c7a58ee71..39607400d6 100644 --- a/services/surfaceflinger/Display/DisplaySnapshot.cpp +++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp @@ -26,11 +26,12 @@ namespace android::display { -DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId, +DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId, uint8_t port, ui::DisplayConnectionType connectionType, DisplayModes&& displayModes, ui::ColorModes&& colorModes, std::optional<DeviceProductInfo>&& deviceProductInfo) : mDisplayId(displayId), + mPort(port), mConnectionType(connectionType), mDisplayModes(std::move(displayModes)), mColorModes(std::move(colorModes)), @@ -62,6 +63,8 @@ ui::ColorModes DisplaySnapshot::filterColorModes(bool supportsWideColor) const { void DisplaySnapshot::dump(utils::Dumper& dumper) const { using namespace std::string_view_literals; + dumper.dump("port"sv, mPort); + dumper.dump("connectionType"sv, ftl::enum_string(mConnectionType)); dumper.dump("colorModes"sv); diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h index 23471f5d8e..0030aad91e 100644 --- a/services/surfaceflinger/Display/DisplaySnapshot.h +++ b/services/surfaceflinger/Display/DisplaySnapshot.h @@ -16,6 +16,7 @@ #pragma once +#include <cstdint> #include <optional> #include <ui/ColorMode.h> @@ -30,13 +31,14 @@ namespace android::display { // Immutable state of a physical display, captured on hotplug. class DisplaySnapshot { public: - DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&, ui::ColorModes&&, - std::optional<DeviceProductInfo>&&); + DisplaySnapshot(PhysicalDisplayId, uint8_t, ui::DisplayConnectionType, DisplayModes&&, + ui::ColorModes&&, std::optional<DeviceProductInfo>&&); DisplaySnapshot(const DisplaySnapshot&) = delete; DisplaySnapshot(DisplaySnapshot&&) = default; PhysicalDisplayId displayId() const { return mDisplayId; } + uint8_t port() const { return mPort; } ui::DisplayConnectionType connectionType() const { return mConnectionType; } std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const; @@ -51,6 +53,7 @@ public: private: const PhysicalDisplayId mDisplayId; + const uint8_t mPort; const ui::DisplayConnectionType mConnectionType; // Effectively const except in move constructor. diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 55ccdefa7a..721cfd31bb 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -1180,6 +1180,7 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port), .name = isPrimary ? "Primary display" : "Secondary display", + .port = port, .deviceProductInfo = std::nullopt}; }(); diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 4d9a9ca06e..022588deef 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -262,7 +262,10 @@ void updateVisibility(LayerSnapshot& snapshot, bool visible) { snapshot.isVisible = visible; if (FlagManager::getInstance().skip_invisible_windows_in_input()) { - snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible); + const bool visibleForInput = + snapshot.isVisible || (snapshot.hasInputInfo() && !snapshot.isHiddenByPolicy()); + snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, + !visibleForInput); } else { // TODO(b/238781169) we are ignoring this compat for now, since we will have // to remove any optimization based on visibility. diff --git a/services/surfaceflinger/PowerAdvisor/Common.h b/services/surfaceflinger/PowerAdvisor/Common.h new file mode 100644 index 0000000000..b4a87dd9a4 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/Common.h @@ -0,0 +1,28 @@ +/* + * Copyright 2024 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 + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include <aidl/android/adpf/ISessionManager.h> +#include <aidl/android/hardware/power/CompositionData.h> +#pragma clang diagnostic pop + +namespace android::adpf { +using namespace ::aidl::android::adpf; +namespace hal = ::aidl::android::hardware::power; +} // namespace android::adpf diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp index c7d0b2c9ef..ff452723d5 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp @@ -28,22 +28,19 @@ #include <optional> #include <android-base/properties.h> +#include <android/binder_libbinder.h> #include <common/trace.h> #include <utils/Log.h> #include <utils/Mutex.h> #include <binder/IServiceManager.h> -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" #include <powermanager/PowerHalController.h> #include <powermanager/PowerHintSessionWrapper.h> -#pragma clang diagnostic pop #include <common/FlagManager.h> #include "PowerAdvisor.h" - -namespace hal = aidl::android::hardware::power; +#include "SessionManager.h" namespace android::adpf::impl { @@ -545,6 +542,18 @@ void PowerAdvisor::setTotalFrameTargetWorkDuration(Duration targetDuration) { mTotalFrameTargetDuration = targetDuration; } +std::shared_ptr<SessionManager> PowerAdvisor::getSessionManager() { + return mSessionManager; +} + +sp<IBinder> PowerAdvisor::getOrCreateSessionManagerForBinder(uid_t uid) { + // Flag guards the creation of SessionManager + if (mSessionManager == nullptr && FlagManager::getInstance().adpf_native_session_manager()) { + mSessionManager = ndk::SharedRefBase::make<SessionManager>(uid); + } + return AIBinder_toPlatformBinder(mSessionManager->asBinder().get()); +} + std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds( std::optional<TimePoint> DisplayTimingData::*sortBy) { std::vector<DisplayId> sortedDisplays; diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h index 458b46d500..43fc21093f 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h @@ -36,6 +36,8 @@ #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" +#include "SessionManager.h" + using namespace std::chrono_literals; namespace android { @@ -47,6 +49,8 @@ class PowerHintSessionWrapper; namespace adpf { +namespace hal = aidl::android::hardware::power; + class PowerAdvisor { public: virtual ~PowerAdvisor() = default; @@ -102,12 +106,18 @@ public: virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0; // Sets the target duration for the entire pipeline including the gpu virtual void setTotalFrameTargetWorkDuration(Duration targetDuration) = 0; + // Get the session manager, if it exists + virtual std::shared_ptr<SessionManager> getSessionManager() = 0; // --- The following methods may run on threads besides SF main --- // Send a hint about an upcoming increase in the CPU workload virtual void notifyCpuLoadUp() = 0; // Send a hint about the imminent start of a new CPU workload virtual void notifyDisplayUpdateImminentAndCpuReset() = 0; + + // --- The following methods specifically run on binder threads --- + // Retrieve a SessionManager for HintManagerService to call + virtual sp<IBinder> getOrCreateSessionManagerForBinder(uid_t uid) = 0; }; namespace impl { @@ -146,11 +156,15 @@ public: void setCompositeEnd(TimePoint compositeEndTime) override; void setDisplays(std::vector<DisplayId>& displayIds) override; void setTotalFrameTargetWorkDuration(Duration targetDuration) override; + std::shared_ptr<SessionManager> getSessionManager() override; // --- The following methods may run on threads besides SF main --- void notifyCpuLoadUp() override; void notifyDisplayUpdateImminentAndCpuReset() override; + // --- The following methods specifically run on binder threads --- + sp<IBinder> getOrCreateSessionManagerForBinder(uid_t uid) override; + private: friend class PowerAdvisorTest; @@ -323,6 +337,8 @@ private: template <aidl::android::hardware::power::ChannelMessage::ChannelMessageContents::Tag T, class In> bool writeHintSessionMessage(In* elements, size_t count) REQUIRES(mHintSessionMutex); + + std::shared_ptr<SessionManager> mSessionManager; }; } // namespace impl diff --git a/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp new file mode 100644 index 0000000000..9f95163e2b --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2024 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 "SessionLayerMap.h" +#include <android/binder_libbinder.h> + +namespace android::adpf { + +void SessionLayerMap::notifySessionsDied(std::vector<int32_t>& sessionIds) { + for (int id : sessionIds) { + auto&& iter = mSessions.find(id); + if (iter != mSessions.end()) { + mSessions.erase(iter); + } + } +} + +void SessionLayerMap::notifyLayersDied(std::vector<int32_t>& layers) { + for (auto&& layer : layers) { + auto&& iter = mLayers.find(layer); + if (iter != mLayers.end()) { + mLayers.erase(iter); + } + } +} + +bool SessionLayerMap::bindSessionIDToLayers(int sessionId, const std::vector<int32_t>& layerIds) { + // If there is no association, just drop from map + if (layerIds.empty()) { + mSessions.erase(sessionId); + return false; + } + + // Ensure session exists + if (!mSessions.contains(sessionId)) { + mSessions.emplace(sessionId, MappedType(sessionId, mLayers)); + } + + MappedType& session = mSessions.at(sessionId); + std::set<int32_t> newLinks; + + // For each incoming link + for (auto&& layerId : layerIds) { + auto&& iter = mLayers.find(layerId); + + // If it's not in the map, add it + if (iter == mLayers.end()) { + mLayers.emplace(layerId, MappedType(layerId, mSessions)); + } + + // Make a ref to it in the session's new association map + newLinks.insert(layerId); + } + + session.swapLinks(std::move(newLinks)); + return true; +} + +void SessionLayerMap::getAssociatedSessions(int32_t layerId, std::vector<int32_t>& sessionIdsOut) { + sessionIdsOut.clear(); + auto&& iter = mLayers.find(layerId); + + if (iter == mLayers.end()) { + return; + } + + // Dump the internal association set into this vector + sessionIdsOut.insert(sessionIdsOut.begin(), iter->second.mLinks.begin(), + iter->second.mLinks.end()); +} + +void SessionLayerMap::getCurrentlyRelevantLayers( + std::unordered_set<int32_t>& currentlyRelevantLayers) { + currentlyRelevantLayers.clear(); + for (auto&& layer : mLayers) { + currentlyRelevantLayers.insert(layer.first); + } +} + +} // namespace android::adpf
\ No newline at end of file diff --git a/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h new file mode 100644 index 0000000000..51808a65fc --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h @@ -0,0 +1,111 @@ +/* + * Copyright 2024 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 <log/log.h> +#include <set> +#include <unordered_map> +#include <unordered_set> + +namespace android::adpf { + +class SessionLayerMap { +public: + // Inform the SessionLayerMap about dead sessions + void notifySessionsDied(std::vector<int32_t>& sessionIds); + // Inform the SessionLayerMap about dead layers + void notifyLayersDied(std::vector<int32_t>& layers); + // Associate a session with a specific set of layer ids + bool bindSessionIDToLayers(int sessionId, const std::vector<int32_t>& layerIds); + // Get the set of sessions that are mapped to a specific layer id + void getAssociatedSessions(int32_t layerId, std::vector<int32_t>& sessionIdsOut); + // Get the set of layers that are currently being tracked + void getCurrentlyRelevantLayers(std::unordered_set<int32_t>& currentlyRelevantLayers); + +private: + struct MappedType { + MappedType(int32_t id, std::unordered_map<int32_t, MappedType>& otherList) + : mId(id), mOtherList(otherList) {}; + MappedType() = delete; + ~MappedType() { swapLinks({}); } + + // Replace the set of associated IDs for this mapped type with a different set of IDs, + // updating only associations which have changed between the two sets + void swapLinks(std::set<int32_t>&& incoming) { + auto&& oldIter = mLinks.begin(); + auto&& newIter = incoming.begin(); + + // Dump all outdated values and insert new ones + while (oldIter != mLinks.end() || newIter != incoming.end()) { + // If there is a value in the new set but not the old set + // We should have already ensured what we're linking to exists + if (oldIter == mLinks.end() || (newIter != incoming.end() && *newIter < *oldIter)) { + addRemoteAssociation(*newIter); + ++newIter; + continue; + } + + // If there is a value in the old set but not the new set + if (newIter == incoming.end() || (oldIter != mLinks.end() && *oldIter < *newIter)) { + dropRemoteAssociation(*oldIter); + ++oldIter; + continue; + } + + // If they're the same, skip + if (*oldIter == *newIter) { + ++oldIter; + ++newIter; + continue; + } + } + + mLinks.swap(incoming); + } + + void addRemoteAssociation(int32_t other) { + auto&& iter = mOtherList.find(other); + if (iter != mOtherList.end()) { + iter->second.mLinks.insert(mId); + } else { + ALOGE("Existing entry in SessionLayerMap, link failed"); + } + } + + void dropRemoteAssociation(int32_t other) { + auto&& iter = mOtherList.find(other); + if (iter != mOtherList.end()) { + iter->second.mLinks.erase(mId); + if (iter->second.mLinks.empty()) { + // This only erases them from the map, not from general tracking + mOtherList.erase(iter); + } + } else { + ALOGE("Missing entry in SessionLayerMap, unlinking failed"); + } + } + + int32_t mId; + std::set<int> mLinks; + std::unordered_map<int32_t, MappedType>& mOtherList; + }; + + std::unordered_map<int32_t, MappedType> mSessions; + std::unordered_map<int32_t, MappedType> mLayers; +}; + +} // namespace android::adpf diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.cpp b/services/surfaceflinger/PowerAdvisor/SessionManager.cpp new file mode 100644 index 0000000000..a855f07914 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionManager.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2024 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 "PowerAdvisor/SessionManager.h" +#include <android/binder_libbinder.h> +#include <android/binder_status.h> +#include <binder/IPCThreadState.h> +#include "FrontEnd/LayerHandle.h" +#include "Layer.h" +#include "SurfaceFlinger.h" + +namespace android::adpf { + +SessionManager::SessionManager(uid_t uid) : mUid(uid) {} + +ndk::ScopedAStatus SessionManager::associateSessionToLayers( + int32_t sessionId, int32_t ownerUid, const std::vector<::ndk::SpAIBinder>& layerTokens) { + std::scoped_lock lock{mSessionManagerMutex}; + + std::vector<int32_t> layerIds; + + for (auto&& token : layerTokens) { + auto platformToken = AIBinder_toPlatformBinder(token.get()); + + // Get the layer id for it + int32_t layerId = + static_cast<int32_t>(surfaceflinger::LayerHandle::getLayerId(platformToken)); + auto&& iter = mTrackedLayerData.find(layerId); + + // Ensure it is being tracked + if (iter == mTrackedLayerData.end()) { + mTrackedLayerData.emplace(layerId, LayerData{.layerId = layerId}); + } + layerIds.push_back(layerId); + } + + // Register the session then track it + if (mMap.bindSessionIDToLayers(sessionId, layerIds) && + !mTrackedSessionData.contains(sessionId)) { + mTrackedSessionData.emplace(sessionId, + SessionData{.sessionId = sessionId, .uid = ownerUid}); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus SessionManager::trackedSessionsDied(const std::vector<int32_t>& sessionIds) { + std::scoped_lock lock{mSessionManagerMutex}; + for (int sessionId : sessionIds) { + mDeadSessions.push_back(sessionId); + mTrackedSessionData.erase(sessionId); + } + + return ndk::ScopedAStatus::ok(); +} + +void SessionManager::updateTrackingState( + const std::vector<std::pair<uint32_t, std::string>>& handles) { + std::scoped_lock lock{mSessionManagerMutex}; + std::vector<int32_t> deadLayers; + for (auto&& handle : handles) { + int32_t handleId = static_cast<int32_t>(handle.first); + auto it = mTrackedLayerData.find(handleId); + if (it != mTrackedLayerData.end()) { + // Track any dead layers to remove from the mapping + mTrackedLayerData.erase(it); + deadLayers.push_back(it->first); + } + } + mMap.notifyLayersDied(deadLayers); + mMap.notifySessionsDied(mDeadSessions); + + mDeadSessions.clear(); + mMap.getCurrentlyRelevantLayers(mCurrentlyRelevantLayers); +} + +bool SessionManager::isLayerRelevant(int32_t layerId) { + return mCurrentlyRelevantLayers.contains(layerId); +} + +} // namespace android::adpf
\ No newline at end of file diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.h b/services/surfaceflinger/PowerAdvisor/SessionManager.h new file mode 100644 index 0000000000..93a80b55ab --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionManager.h @@ -0,0 +1,102 @@ +/* + * Copyright 2024 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 <aidl/android/adpf/BnSessionManager.h> +#include <sys/types.h> + +#include <utils/Thread.h> +#include "Common.h" +#include "SessionLayerMap.h" + +#include <string> + +namespace android { + +class Layer; + +namespace adpf { +namespace impl { + +class PowerAdvisor; + +} + +// Talks to HMS to manage sessions for PowerHAL +class SessionManager : public BnSessionManager { +public: + SessionManager(uid_t uid); + + // ISessionManager binder methods + ndk::ScopedAStatus trackedSessionsDied(const std::vector<int32_t>& in_sessionId) override; + ndk::ScopedAStatus associateSessionToLayers( + int32_t sessionId, int32_t ownerUid, + const std::vector<::ndk::SpAIBinder>& layers) override; + + // Update the lifecycles of any tracked sessions or layers. This is intended to accepts the + // "destroyedHandles" object from updateLayerSnapshots in SF, and should reflect that type + void updateTrackingState(const std::vector<std::pair<uint32_t, std::string>>& handles); + +private: + // Session metadata tracked by the mTrackedSessionData map + struct SessionData { + int32_t sessionId; + int uid; + }; + + // Layer metadata tracked by the mTrackedSessionData map + struct LayerData { + int32_t layerId; + }; + + // Checks if the layer is currently associated with a specific session in the SessionLayerMap + // This helps us know which layers might be included in an update for the HAL + bool isLayerRelevant(int32_t layerId); + + // The UID of whoever created our ISessionManager connection + const uid_t mUid; + + // State owned by the main thread + + // Set of layers that are currently being tracked in the SessionLayerMap. This is used to + // filter out which layers we actually care about during the latching process + std::unordered_set<int32_t> mCurrentlyRelevantLayers; + + // Tracks active associations between sessions and layers. Items in this map can be thought of + // as "active" connections, and any session or layer not in this map will not receive updates or + // be collected in SurfaceFlinger + SessionLayerMap mMap; + + // The list of currently-living layers which have ever been tracked, this is used to persist any + // data we want to track across potential mapping disconnects, and to determine when to send + // death updates + std::unordered_map<int32_t, LayerData> mTrackedLayerData; + + // The list of currently-living sessions which have ever been tracked, this is used to persist + // any data we want to track across mapping disconnects + std::unordered_map<int32_t, SessionData> mTrackedSessionData; + + // State owned by mSessionManagerMutex + + std::mutex mSessionManagerMutex; + + // The list of sessions that have died since we last called updateTrackingState + std::vector<int32_t> mDeadSessions GUARDED_BY(mSessionManagerMutex); +}; + +} // namespace adpf +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 21d3396ebe..d3483b0cb0 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -346,7 +346,6 @@ void RegionSamplingThread::captureSample() { constexpr bool kRegionSampling = true; constexpr bool kGrayscale = false; constexpr bool kIsProtected = false; - constexpr bool kAttachGainmap = false; SurfaceFlinger::RenderAreaBuilderVariant renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, @@ -358,7 +357,7 @@ void RegionSamplingThread::captureSample() { mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); FenceResult fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, - kIsProtected, kAttachGainmap, nullptr, displayState, layers) + kIsProtected, nullptr, displayState, layers) .get(); if (fenceResult.ok()) { fenceResult.value()->waitForever(LOG_TAG); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 3fdddac52a..a2cdd460ca 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -209,6 +209,7 @@ public: ftl::FakeGuard guard(kMainThreadContext); resyncToHardwareVsyncLocked(id, allowToEnable, modePtr); } + void resync() override EXCLUDES(mDisplayLock); void forceNextResync() { mLastResyncTime = 0; } // Passes a vsync sample to VsyncController. Returns true if @@ -470,7 +471,6 @@ private: bool throttleVsync(TimePoint, uid_t) override; // Get frame interval Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock); - void resync() override EXCLUDES(mDisplayLock); void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock); std::unique_ptr<EventThread> mRenderEventThread; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 59b1917740..220133de66 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -126,7 +126,6 @@ #include <gui/SchedulingPolicy.h> #include <gui/SyncScreenCaptureListener.h> #include <ui/DisplayIdentification.h> -#include "ActivePictureUpdater.h" #include "BackgroundExecutor.h" #include "Client.h" #include "ClientCache.h" @@ -877,6 +876,9 @@ renderengine::RenderEngine::BlurAlgorithm chooseBlurAlgorithm(bool supportsBlur) } else if (algorithm == "kawase2") { return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER; } else { + if (FlagManager::getInstance().window_blur_kawase2()) { + return renderengine::RenderEngine::BlurAlgorithm::KAWASE_DUAL_FILTER; + } return renderengine::RenderEngine::BlurAlgorithm::KAWASE; } } @@ -1441,14 +1443,14 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToke return future.get(); } -void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { +bool SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { SFTRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); const auto pendingModeOpt = mDisplayModeController.getPendingMode(displayId); if (!pendingModeOpt) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. - return; + return true; } const auto& activeMode = pendingModeOpt->mode; @@ -1463,8 +1465,8 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { state.physical->activeMode = activeMode.modePtr.get(); processDisplayChangesLocked(); - // processDisplayChangesLocked will update all necessary components so we're done here. - return; + // The DisplayDevice has been destroyed, so abort the commit for the now dead FrameTargeter. + return false; } mDisplayModeController.finalizeModeChange(displayId, activeMode.modePtr->getId(), @@ -1475,6 +1477,8 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { if (pendingModeOpt->emitEvent) { mScheduler->onDisplayModeChanged(displayId, activeMode, /*clearContentRequirements*/ true); } + + return true; } void SurfaceFlinger::dropModeRequest(PhysicalDisplayId displayId) { @@ -2656,7 +2660,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, for (const auto [displayId, _] : frameTargets) { if (mDisplayModeController.isModeSetPending(displayId)) { - finalizeDisplayModeChange(displayId); + if (!finalizeDisplayModeChange(displayId)) { + mScheduler->scheduleFrame(); + return false; + } } } } @@ -2785,12 +2792,43 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); refreshArgs.outputs.reserve(displays.size()); + // Track layer stacks of physical displays that might be added to CompositionEngine + // output. Layer stacks are not tracked in Display when we iterate through + // frameTargeters. Cross-referencing layer stacks allows us to filter out displays + // by ID with duplicate layer stacks before adding them to CompositionEngine output. + ui::DisplayMap<DisplayId, ui::LayerStack> physicalDisplayLayerStacks; + for (auto& [_, display] : displays) { + const auto id = PhysicalDisplayId::tryCast(display->getId()); + if (id && frameTargeters.contains(*id)) { + physicalDisplayLayerStacks.try_emplace(*id, display->getLayerStack()); + } + } + + // Tracks layer stacks of displays that are added to CompositionEngine output. + ui::DisplayMap<ui::LayerStack, ftl::Unit> outputLayerStacks; + auto isOutputLayerStack = [&outputLayerStacks](DisplayId id, ui::LayerStack layerStack) { + if (FlagManager::getInstance().reject_dupe_layerstacks() && + outputLayerStacks.contains(layerStack)) { + // TODO: remove log and DisplayId from params once reject_dupe_layerstacks flag is + // removed + ALOGD("Existing layer stack ID %d output to another display %" PRIu64 + ", dropping display from outputs", + layerStack.id, id.value); + return true; + } + outputLayerStacks.try_emplace(layerStack); + return false; + }; + // Add outputs for physical displays. for (const auto& [id, targeter] : frameTargeters) { ftl::FakeGuard guard(mStateLock); if (const auto display = getCompositionDisplayLocked(id)) { - refreshArgs.outputs.push_back(display); + const auto layerStack = physicalDisplayLayerStacks.get(id)->get(); + if (!isOutputLayerStack(display->getId(), layerStack)) { + refreshArgs.outputs.push_back(display); + } } refreshArgs.frameTargets.try_emplace(id, &targeter->target()); @@ -2807,7 +2845,9 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( if (!refreshRate.isValid() || mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) { - refreshArgs.outputs.push_back(display->getCompositionDisplay()); + if (!isOutputLayerStack(display->getId(), display->getLayerStack())) { + refreshArgs.outputs.push_back(display->getCompositionDisplay()); + } } } } @@ -2911,7 +2951,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( layer->setWasClientComposed(compositionResult.lastClientCompositionFence); } if (com_android_graphics_libgui_flags_apply_picture_profiles()) { - mActivePictureUpdater.onLayerComposed(*layer, *layerFE, compositionResult); + mActivePictureTracker.onLayerComposed(*layer, *layerFE, compositionResult); } } @@ -3223,8 +3263,8 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>> hdrInfoListeners; bool haveNewHdrInfoListeners = false; - sp<gui::IActivePictureListener> activePictureListener; - bool haveNewActivePictureListener = false; + ActivePictureTracker::Listeners activePictureListenersToAdd; + ActivePictureTracker::Listeners activePictureListenersToRemove; { Mutex::Autolock lock(mStateLock); if (mFpsReporter) { @@ -3246,9 +3286,8 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, haveNewHdrInfoListeners = mAddingHDRLayerInfoListener; // grab this with state lock mAddingHDRLayerInfoListener = false; - activePictureListener = mActivePictureListener; - haveNewActivePictureListener = mHaveNewActivePictureListener; - mHaveNewActivePictureListener = false; + std::swap(activePictureListenersToAdd, mActivePictureListenersToAdd); + std::swap(activePictureListenersToRemove, mActivePictureListenersToRemove); } if (haveNewHdrInfoListeners || mHdrLayerInfoChanged) { @@ -3312,14 +3351,10 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, mHdrLayerInfoChanged = false; if (com_android_graphics_libgui_flags_apply_picture_profiles()) { - // Track, update and notify changes to active pictures - layers that are undergoing picture - // processing - if (mActivePictureUpdater.updateAndHasChanged() || haveNewActivePictureListener) { - if (activePictureListener) { - activePictureListener->onActivePicturesChanged( - mActivePictureUpdater.getActivePictures()); - } - } + // Track, update and notify changes to active pictures - layers that are undergoing + // picture processing + mActivePictureTracker.updateAndNotifyListeners(activePictureListenersToAdd, + activePictureListenersToRemove); } mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); @@ -3631,10 +3666,13 @@ std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDispl deviceProductInfo = snapshot.deviceProductInfo(); } + // Use the cached port via snapshot because we are updating an existing + // display on reconnect. const auto it = mPhysicalDisplays.try_replace(displayId, display.token(), displayId, - snapshot.connectionType(), std::move(displayModes), - std::move(colorModes), std::move(deviceProductInfo)); + snapshot.port(), snapshot.connectionType(), + std::move(displayModes), std::move(colorModes), + std::move(deviceProductInfo)); auto& state = mCurrentState.displays.editValueFor(it->second.token()); state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. @@ -3647,7 +3685,7 @@ std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDispl const ui::DisplayConnectionType connectionType = getHwComposer().getDisplayConnectionType(displayId); - mPhysicalDisplays.try_emplace(displayId, token, displayId, connectionType, + mPhysicalDisplays.try_emplace(displayId, token, displayId, info.port, connectionType, std::move(displayModes), std::move(colorModes), std::move(info.deviceProductInfo)); @@ -4563,6 +4601,7 @@ void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule sche SFTRACE_INT("mTransactionFlags", transactionFlags); if (const bool scheduled = transactionFlags & mask; !scheduled) { + mScheduler->resync(); scheduleCommit(frameHint); } else if (frameHint == FrameHint::kActive) { // Even if the next frame is already scheduled, we should reset the idle timer @@ -7145,8 +7184,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, displayWeak, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, - captureArgs.attachGainmap, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, captureListener); } void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args, @@ -7203,7 +7241,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args static_cast<ui::Dataspace>(args.dataspace), displayWeak, options), getLayerSnapshotsFn, size, static_cast<ui::PixelFormat>(args.pixelFormat), - kAllowProtected, kGrayscale, args.attachGainmap, captureListener); + kAllowProtected, kGrayscale, captureListener); } ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) { @@ -7314,8 +7352,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, - captureArgs.attachGainmap, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, captureListener); } // Creates a Future release fence for a layer and keeps track of it in a list to @@ -7373,7 +7410,7 @@ std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapsho void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool allowProtected, bool grayscale, bool attachGainmap, + bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); @@ -7388,6 +7425,10 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil std::vector<std::pair<Layer*, sp<LayerFE>>> layers; auto displayState = getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); + const bool hasHdrLayer = std::any_of(layers.cbegin(), layers.cend(), [this](const auto& layer) { + return isHdrLayer(*(layer.second->mSnapshot.get())); + }); + const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { @@ -7416,9 +7457,51 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), renderengine::impl::ExternalTexture::Usage:: WRITEABLE); - auto futureFence = - captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale, - isProtected, attachGainmap, captureListener, displayState, layers); + + std::shared_ptr<renderengine::impl::ExternalTexture> hdrTexture; + std::shared_ptr<renderengine::impl::ExternalTexture> gainmapTexture; + + bool hintForSeamless = std::visit( + [](auto&& arg) { + return arg.options.test(RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION); + }, + renderAreaBuilder); + if (hasHdrLayer && !hintForSeamless && FlagManager::getInstance().true_hdr_screenshots()) { + const auto hdrBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */, + buffer->getUsage(), "screenshot-hdr"); + const auto gainmapBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + buffer->getPixelFormat(), 1 /* layerCount */, + buffer->getUsage(), "screenshot-gainmap"); + + const status_t hdrBufferStatus = hdrBuffer->initCheck(); + const status_t gainmapBufferStatus = gainmapBuffer->initCheck(); + + if (hdrBufferStatus != OK || gainmapBufferStatus != -OK) { + if (hdrBufferStatus != OK) { + ALOGW("%s: Buffer failed to allocate for hdr: %d. Screenshoting SDR instead.", + __func__, hdrBufferStatus); + } else { + ALOGW("%s: Buffer failed to allocate for gainmap: %d. Screenshoting SDR instead.", + __func__, gainmapBufferStatus); + } + } else { + hdrTexture = std::make_shared< + renderengine::impl::ExternalTexture>(hdrBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + gainmapTexture = std::make_shared< + renderengine::impl::ExternalTexture>(gainmapBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + } + } + + auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, + grayscale, isProtected, captureListener, displayState, + layers, hdrTexture, gainmapTexture); futureFence.get(); } @@ -7461,10 +7544,11 @@ SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& r ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, bool attachGainmap, - const sp<IScreenCaptureListener>& captureListener, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { + bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, + const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer, + const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer) { SFTRACE_CALL(); ScreenCaptureResults captureResults; @@ -7480,74 +7564,40 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( } return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } + float displayBrightnessNits = displayState.value().displayBrightnessNits; float sdrWhitePointNits = displayState.value().sdrWhitePointNits; - ftl::SharedFuture<FenceResult> renderFuture = - renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, - captureResults, displayState, layers); - - if (captureResults.capturedHdrLayers && attachGainmap && - FlagManager::getInstance().true_hdr_screenshots()) { - sp<GraphicBuffer> hdrBuffer = - getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), - HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */, - buffer->getUsage(), "screenshot-hdr"); - sp<GraphicBuffer> gainmapBuffer = - getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), - buffer->getPixelFormat(), 1 /* layerCount */, - buffer->getUsage(), "screenshot-gainmap"); - - const status_t bufferStatus = hdrBuffer->initCheck(); - const status_t gainmapBufferStatus = gainmapBuffer->initCheck(); - - if (bufferStatus != OK) { - ALOGW("%s: Buffer failed to allocate for hdr: %d. Screenshoting SDR instead.", __func__, - bufferStatus); - } else if (gainmapBufferStatus != OK) { - ALOGW("%s: Buffer failed to allocate for gainmap: %d. Screenshoting SDR instead.", - __func__, gainmapBufferStatus); - } else { - captureResults.optionalGainMap = gainmapBuffer; - const auto hdrTexture = std::make_shared< - renderengine::impl::ExternalTexture>(hdrBuffer, getRenderEngine(), - renderengine::impl::ExternalTexture:: - Usage::WRITEABLE); - const auto gainmapTexture = std::make_shared< - renderengine::impl::ExternalTexture>(gainmapBuffer, getRenderEngine(), - renderengine::impl::ExternalTexture:: - Usage::WRITEABLE); - ScreenCaptureResults unusedResults; - ftl::SharedFuture<FenceResult> hdrRenderFuture = - renderScreenImpl(renderArea.get(), hdrTexture, regionSampling, grayscale, - isProtected, unusedResults, displayState, layers); - - renderFuture = - ftl::Future(std::move(renderFuture)) - .then([&, hdrRenderFuture = std::move(hdrRenderFuture), - displayBrightnessNits, sdrWhitePointNits, - dataspace = captureResults.capturedDataspace, buffer, hdrTexture, - gainmapTexture](FenceResult fenceResult) -> FenceResult { - if (!fenceResult.ok()) { - return fenceResult; - } - - auto hdrFenceResult = hdrRenderFuture.get(); - - if (!hdrFenceResult.ok()) { - return hdrFenceResult; - } + ftl::SharedFuture<FenceResult> renderFuture; + + if (hdrBuffer && gainmapBuffer) { + ftl::SharedFuture<FenceResult> hdrRenderFuture = + renderScreenImpl(renderArea.get(), hdrBuffer, regionSampling, grayscale, + isProtected, captureResults, displayState, layers); + captureResults.buffer = buffer->getBuffer(); + captureResults.optionalGainMap = gainmapBuffer->getBuffer(); + + renderFuture = + ftl::Future(std::move(hdrRenderFuture)) + .then([&, displayBrightnessNits, sdrWhitePointNits, + dataspace = captureResults.capturedDataspace, buffer, hdrBuffer, + gainmapBuffer](FenceResult fenceResult) -> FenceResult { + if (!fenceResult.ok()) { + return fenceResult; + } - return getRenderEngine() - .drawGainmap(buffer, fenceResult.value()->get(), hdrTexture, - hdrFenceResult.value()->get(), - displayBrightnessNits / sdrWhitePointNits, - static_cast<ui::Dataspace>(dataspace), - gainmapTexture) - .get(); - }) - .share(); - }; + return getRenderEngine() + .tonemapAndDrawGainmap(hdrBuffer, fenceResult.value()->get(), + displayBrightnessNits / + sdrWhitePointNits, + static_cast<ui::Dataspace>(dataspace), + buffer, gainmapBuffer) + .get(); + }) + .share(); + } else { + renderFuture = renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, + isProtected, captureResults, displayState, layers); } if (captureListener) { @@ -7569,8 +7619,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( const RenderArea* renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { SFTRACE_CALL(); for (auto& [_, layerFE] : layers) { @@ -7638,9 +7688,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( } auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace, - sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, - layers = std::move(layers), layerStack, regionSampling, - renderArea = std::move(renderArea), renderIntent, + sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, layers, + layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent, enableLocalTonemapping]() -> FenceResult { std::unique_ptr<compositionengine::CompositionEngine> compositionEngine = mFactory.createCompositionEngine(); @@ -8171,12 +8220,20 @@ void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t con })); } -void SurfaceFlinger::setActivePictureListener(const sp<gui::IActivePictureListener>& listener) { - if (com_android_graphics_libgui_flags_apply_picture_profiles()) { - Mutex::Autolock lock(mStateLock); - mActivePictureListener = listener; - mHaveNewActivePictureListener = listener != nullptr; - } +void SurfaceFlinger::addActivePictureListener(const sp<gui::IActivePictureListener>& listener) { + Mutex::Autolock lock(mStateLock); + std::erase_if(mActivePictureListenersToRemove, [listener](const auto& otherListener) { + return IInterface::asBinder(listener) == IInterface::asBinder(otherListener); + }); + mActivePictureListenersToAdd.push_back(listener); +} + +void SurfaceFlinger::removeActivePictureListener(const sp<gui::IActivePictureListener>& listener) { + Mutex::Autolock lock(mStateLock); + std::erase_if(mActivePictureListenersToAdd, [listener](const auto& otherListener) { + return IInterface::asBinder(listener) == IInterface::asBinder(otherListener); + }); + mActivePictureListenersToRemove.push_back(listener); } std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData( @@ -9129,11 +9186,20 @@ binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener( return binderStatusFromStatusT(status); } -binder::Status SurfaceComposerAIDL::setActivePictureListener( +binder::Status SurfaceComposerAIDL::addActivePictureListener( + const sp<gui::IActivePictureListener>& listener) { + status_t status = checkObservePictureProfilesPermission(); + if (status == OK) { + mFlinger->addActivePictureListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeActivePictureListener( const sp<gui::IActivePictureListener>& listener) { status_t status = checkObservePictureProfilesPermission(); if (status == OK) { - mFlinger->setActivePictureListener(listener); + mFlinger->removeActivePictureListener(listener); } return binderStatusFromStatusT(status); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1e2c08747b..c85c0846c5 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -69,7 +69,7 @@ #include <ui/FenceResult.h> #include <common/FlagManager.h> -#include "ActivePictureUpdater.h" +#include "ActivePictureTracker.h" #include "BackgroundExecutor.h" #include "Display/DisplayModeController.h" #include "Display/PhysicalDisplay.h" @@ -667,7 +667,9 @@ private: void updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, int32_t maxLevel); - void setActivePictureListener(const sp<gui::IActivePictureListener>& listener); + void addActivePictureListener(const sp<gui::IActivePictureListener>& listener); + + void removeActivePictureListener(const sp<gui::IActivePictureListener>& listener); // IBinder::DeathRecipient overrides: void binderDied(const wp<IBinder>& who) override; @@ -730,7 +732,11 @@ private: Fps maxFps); void initiateDisplayModeChanges() REQUIRES(kMainThreadContext) REQUIRES(mStateLock); - void finalizeDisplayModeChange(PhysicalDisplayId) REQUIRES(kMainThreadContext) + + // Returns whether the commit stage should proceed. The return value is ignored when finalizing + // immediate mode changes, which happen toward the end of the commit stage. + // TODO: b/355427258 - Remove the return value once the `synced_resolution_switch` flag is live. + bool finalizeDisplayModeChange(PhysicalDisplayId) REQUIRES(kMainThreadContext) REQUIRES(mStateLock); void dropModeRequest(PhysicalDisplayId) REQUIRES(kMainThreadContext); @@ -872,7 +878,7 @@ private: void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, - bool grayscale, bool attachGainmap, const sp<IScreenCaptureListener>&); + bool grayscale, const sp<IScreenCaptureListener>&); std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); @@ -880,16 +886,17 @@ private: ftl::SharedFuture<FenceResult> captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, bool attachGainmap, - const sp<IScreenCaptureListener>& captureListener, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); + bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, + const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer = nullptr, + const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer = nullptr); ftl::SharedFuture<FenceResult> renderScreenImpl( const RenderArea*, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); void readPersistentProperties(); @@ -1402,9 +1409,9 @@ private: std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners GUARDED_BY(mStateLock); - sp<gui::IActivePictureListener> mActivePictureListener GUARDED_BY(mStateLock); - bool mHaveNewActivePictureListener GUARDED_BY(mStateLock); - ActivePictureUpdater mActivePictureUpdater GUARDED_BY(kMainThreadContext); + ActivePictureTracker mActivePictureTracker GUARDED_BY(kMainThreadContext); + ActivePictureTracker::Listeners mActivePictureListenersToAdd GUARDED_BY(mStateLock); + ActivePictureTracker::Listeners mActivePictureListenersToRemove GUARDED_BY(mStateLock); std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint; @@ -1641,8 +1648,8 @@ public: binder::Status flushJankData(int32_t layerId) override; binder::Status removeJankListener(int32_t layerId, const sp<gui::IJankListener>& listener, int64_t afterVsync) override; - binder::Status setActivePictureListener(const sp<gui::IActivePictureListener>& listener); - binder::Status clearActivePictureListener(); + binder::Status addActivePictureListener(const sp<gui::IActivePictureListener>& listener); + binder::Status removeActivePictureListener(const sp<gui::IActivePictureListener>& listener); private: static const constexpr bool kUsePermissionCache = true; diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp index 63c1b37166..d2ffcc0f73 100644 --- a/services/surfaceflinger/Tracing/tools/Android.bp +++ b/services/surfaceflinger/Tracing/tools/Android.bp @@ -27,6 +27,7 @@ cc_binary { defaults: [ "libsurfaceflinger_mocks_defaults", "librenderengine_deps", + "poweradvisor_deps", "surfaceflinger_defaults", "libsurfaceflinger_common_deps", ], diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index 858f7598ca..e80cd78cbd 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -112,59 +112,63 @@ void FlagManager::dump(std::string& result) const { DUMP_LEGACY_SERVER_FLAG(use_skia_tracing); /// Trunk stable server (R/W) flags /// - DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display); DUMP_ACONFIG_FLAG(adpf_gpu_sf); DUMP_ACONFIG_FLAG(adpf_native_session_manager); DUMP_ACONFIG_FLAG(adpf_use_fmq_channel); DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout); + DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display); /// Trunk stable readonly flags /// + /// IMPORTANT - please keep alphabetize to reduce merge conflicts + DUMP_ACONFIG_FLAG(add_sf_skipped_frames_to_trace); DUMP_ACONFIG_FLAG(adpf_fmq_sf); + DUMP_ACONFIG_FLAG(allow_n_vsyncs_in_targeter); DUMP_ACONFIG_FLAG(arr_setframerate_gte_enum); - DUMP_ACONFIG_FLAG(connected_display); - DUMP_ACONFIG_FLAG(enable_small_area_detection); - DUMP_ACONFIG_FLAG(stable_edid_ids); - DUMP_ACONFIG_FLAG(frame_rate_category_mrr); - DUMP_ACONFIG_FLAG(misc1); - DUMP_ACONFIG_FLAG(vrr_config); - DUMP_ACONFIG_FLAG(hdcp_level_hal); - DUMP_ACONFIG_FLAG(multithreaded_present); - DUMP_ACONFIG_FLAG(add_sf_skipped_frames_to_trace); - DUMP_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency); + DUMP_ACONFIG_FLAG(begone_bright_hlg); DUMP_ACONFIG_FLAG(cache_when_source_crop_layer_only_moved); - DUMP_ACONFIG_FLAG(enable_fro_dependent_features); + DUMP_ACONFIG_FLAG(commit_not_composited); + DUMP_ACONFIG_FLAG(connected_display); + DUMP_ACONFIG_FLAG(connected_display_hdr); + DUMP_ACONFIG_FLAG(correct_dpi_with_display_size); + DUMP_ACONFIG_FLAG(deprecate_frame_tracker); + DUMP_ACONFIG_FLAG(deprecate_vsync_sf); + DUMP_ACONFIG_FLAG(detached_mirror); + DUMP_ACONFIG_FLAG(display_config_error_hal); DUMP_ACONFIG_FLAG(display_protected); + DUMP_ACONFIG_FLAG(dont_skip_on_early_ro); + DUMP_ACONFIG_FLAG(enable_fro_dependent_features); + DUMP_ACONFIG_FLAG(enable_layer_command_batching); + DUMP_ACONFIG_FLAG(enable_small_area_detection); + DUMP_ACONFIG_FLAG(filter_frames_before_trace_starts); + DUMP_ACONFIG_FLAG(flush_buffer_slots_to_uncache); + DUMP_ACONFIG_FLAG(force_compile_graphite_renderengine); DUMP_ACONFIG_FLAG(fp16_client_target); + DUMP_ACONFIG_FLAG(frame_rate_category_mrr); DUMP_ACONFIG_FLAG(game_default_frame_rate); - DUMP_ACONFIG_FLAG(enable_layer_command_batching); - DUMP_ACONFIG_FLAG(vulkan_renderengine); - DUMP_ACONFIG_FLAG(renderable_buffer_usage); - DUMP_ACONFIG_FLAG(vrr_bugfix_24q4); - DUMP_ACONFIG_FLAG(vrr_bugfix_dropped_frame); - DUMP_ACONFIG_FLAG(restore_blur_step); - DUMP_ACONFIG_FLAG(dont_skip_on_early_ro); - DUMP_ACONFIG_FLAG(no_vsyncs_on_screen_off); - DUMP_ACONFIG_FLAG(protected_if_client); - DUMP_ACONFIG_FLAG(idle_screen_refresh_rate_timeout); DUMP_ACONFIG_FLAG(graphite_renderengine); - DUMP_ACONFIG_FLAG(filter_frames_before_trace_starts); + DUMP_ACONFIG_FLAG(hdcp_level_hal); + DUMP_ACONFIG_FLAG(idle_screen_refresh_rate_timeout); DUMP_ACONFIG_FLAG(latch_unsignaled_with_auto_refresh_changed); - DUMP_ACONFIG_FLAG(deprecate_vsync_sf); - DUMP_ACONFIG_FLAG(allow_n_vsyncs_in_targeter); - DUMP_ACONFIG_FLAG(detached_mirror); - DUMP_ACONFIG_FLAG(commit_not_composited); - DUMP_ACONFIG_FLAG(correct_dpi_with_display_size); DUMP_ACONFIG_FLAG(local_tonemap_screenshots); + DUMP_ACONFIG_FLAG(misc1); + DUMP_ACONFIG_FLAG(multithreaded_present); + DUMP_ACONFIG_FLAG(no_vsyncs_on_screen_off); DUMP_ACONFIG_FLAG(override_trusted_overlay); - DUMP_ACONFIG_FLAG(flush_buffer_slots_to_uncache); - DUMP_ACONFIG_FLAG(force_compile_graphite_renderengine); + DUMP_ACONFIG_FLAG(protected_if_client); + DUMP_ACONFIG_FLAG(reject_dupe_layerstacks); + DUMP_ACONFIG_FLAG(renderable_buffer_usage); + DUMP_ACONFIG_FLAG(restore_blur_step); + DUMP_ACONFIG_FLAG(skip_invisible_windows_in_input); + DUMP_ACONFIG_FLAG(stable_edid_ids); DUMP_ACONFIG_FLAG(trace_frame_rate_override); DUMP_ACONFIG_FLAG(true_hdr_screenshots); - DUMP_ACONFIG_FLAG(display_config_error_hal); - DUMP_ACONFIG_FLAG(connected_display_hdr); - DUMP_ACONFIG_FLAG(deprecate_frame_tracker); - DUMP_ACONFIG_FLAG(skip_invisible_windows_in_input); - DUMP_ACONFIG_FLAG(begone_bright_hlg); + DUMP_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency); + DUMP_ACONFIG_FLAG(vrr_bugfix_24q4); + DUMP_ACONFIG_FLAG(vrr_bugfix_dropped_frame); + DUMP_ACONFIG_FLAG(vrr_config); + DUMP_ACONFIG_FLAG(vulkan_renderengine); + DUMP_ACONFIG_FLAG(window_blur_kawase2); + /// IMPORTANT - please keep alphabetize to reduce merge conflicts #undef DUMP_ACONFIG_FLAG #undef DUMP_LEGACY_SERVER_FLAG @@ -264,6 +268,8 @@ FLAG_MANAGER_ACONFIG_FLAG(connected_display_hdr, "debug.sf.connected_display_hdr FLAG_MANAGER_ACONFIG_FLAG(deprecate_frame_tracker, ""); FLAG_MANAGER_ACONFIG_FLAG(skip_invisible_windows_in_input, ""); FLAG_MANAGER_ACONFIG_FLAG(begone_bright_hlg, "debug.sf.begone_bright_hlg"); +FLAG_MANAGER_ACONFIG_FLAG(window_blur_kawase2, ""); +FLAG_MANAGER_ACONFIG_FLAG(reject_dupe_layerstacks, ""); /// Trunk stable server (R/W) flags /// FLAG_MANAGER_ACONFIG_FLAG(refresh_rate_overlay_on_external_display, "") diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index 05af721681..c7f97b4008 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -48,61 +48,65 @@ public: bool use_skia_tracing() const; /// Trunk stable server (R/W) flags /// - bool refresh_rate_overlay_on_external_display() const; bool adpf_gpu_sf() const; - bool adpf_use_fmq_channel() const; bool adpf_native_session_manager() const; + bool adpf_use_fmq_channel() const; bool adpf_use_fmq_channel_fixed() const; bool graphite_renderengine_preview_rollout() const; + bool refresh_rate_overlay_on_external_display() const; /// Trunk stable readonly flags /// - bool arr_setframerate_gte_enum() const; - bool adpf_fmq_sf() const; - bool connected_display() const; - bool frame_rate_category_mrr() const; - bool enable_small_area_detection() const; - bool stable_edid_ids() const; - bool misc1() const; - bool vrr_config() const; - bool hdcp_level_hal() const; - bool multithreaded_present() const; + /// IMPORTANT - please keep alphabetize to reduce merge conflicts bool add_sf_skipped_frames_to_trace() const; - bool use_known_refresh_rate_for_fps_consistency() const; + bool adpf_fmq_sf() const; + bool allow_n_vsyncs_in_targeter() const; + bool arr_setframerate_gte_enum() const; + bool begone_bright_hlg() const; bool cache_when_source_crop_layer_only_moved() const; - bool enable_fro_dependent_features() const; + bool commit_not_composited() const; + bool connected_display() const; + bool connected_display_hdr() const; + bool correct_dpi_with_display_size() const; + bool deprecate_frame_tracker() const; + bool deprecate_vsync_sf() const; + bool detached_mirror() const; + bool display_config_error_hal() const; bool display_protected() const; + bool dont_skip_on_early_ro() const; + bool enable_fro_dependent_features() const; + bool enable_layer_command_batching() const; + bool enable_small_area_detection() const; + bool filter_frames_before_trace_starts() const; + bool flush_buffer_slots_to_uncache() const; + bool force_compile_graphite_renderengine() const; bool fp16_client_target() const; + bool frame_rate_category_mrr() const; bool game_default_frame_rate() const; - bool enable_layer_command_batching() const; - bool vulkan_renderengine() const; - bool vrr_bugfix_24q4() const; - bool vrr_bugfix_dropped_frame() const; - bool renderable_buffer_usage() const; - bool restore_blur_step() const; - bool dont_skip_on_early_ro() const; - bool no_vsyncs_on_screen_off() const; - bool protected_if_client() const; - bool idle_screen_refresh_rate_timeout() const; bool graphite_renderengine() const; - bool filter_frames_before_trace_starts() const; + bool hdcp_level_hal() const; + bool idle_screen_refresh_rate_timeout() const; bool latch_unsignaled_with_auto_refresh_changed() const; - bool deprecate_vsync_sf() const; - bool allow_n_vsyncs_in_targeter() const; - bool detached_mirror() const; - bool commit_not_composited() const; - bool correct_dpi_with_display_size() const; bool local_tonemap_screenshots() const; + bool luts_api() const; + bool misc1() const; + bool multithreaded_present() const; + bool no_vsyncs_on_screen_off() const; bool override_trusted_overlay() const; - bool flush_buffer_slots_to_uncache() const; - bool force_compile_graphite_renderengine() const; + bool protected_if_client() const; + bool reject_dupe_layerstacks() const; + bool renderable_buffer_usage() const; + bool restore_blur_step() const; + bool skip_invisible_windows_in_input() const; + bool stable_edid_ids() const; bool trace_frame_rate_override() const; bool true_hdr_screenshots() const; - bool display_config_error_hal() const; - bool connected_display_hdr() const; - bool deprecate_frame_tracker() const; - bool skip_invisible_windows_in_input() const; - bool begone_bright_hlg() const; - bool luts_api() const; + bool use_known_refresh_rate_for_fps_consistency() const; + bool vrr_bugfix_24q4() const; + bool vrr_bugfix_dropped_frame() const; + bool vrr_config() const; + bool vulkan_renderengine() const; + bool window_blur_kawase2() const; + /// IMPORTANT - please keep alphabetize to reduce merge conflicts protected: // overridden for unit tests diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index fc0fabd3e7..b28d2697c5 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -217,6 +217,17 @@ flag { } # no_vsyncs_on_screen_off flag { + name: "reject_dupe_layerstacks" + namespace: "window_surfaces" + description: "Reject duplicate layerstacks for displays" + bug: "370358572" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } + } # reject_dupe_layerstacks + +flag { name: "single_hop_screenshot" namespace: "window_surfaces" description: "Only access SF main thread once during a screenshot" @@ -295,4 +306,11 @@ flag { } } # vrr_bugfix_dropped_frame +flag { + name: "window_blur_kawase2" + namespace: "core_graphics" + description: "Flag for using Kawase2 algorithm for window blur" + bug: "353826438" +} # window_blur_kawase2 + # IMPORTANT - please keep alphabetize to reduce merge conflicts diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 4d5c0fd1de..b5f7a74347 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -52,7 +52,7 @@ cc_test { "LayerTypeTransaction_test.cpp", "LayerUpdate_test.cpp", "MirrorLayer_test.cpp", - "MultiDisplayLayerBounds_test.cpp", + "MultiDisplay_test.cpp", "RefreshRateOverlay_test.cpp", "RelativeZ_test.cpp", "ReleaseBufferCallback_test.cpp", diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplay_test.cpp index 56cf13d7fe..54bb253526 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplay_test.cpp @@ -19,6 +19,7 @@ #pragma clang diagnostic ignored "-Wconversion" #include <common/FlagManager.h> +#include <gui/IConsumerListener.h> #include <ui/DisplayState.h> #include "LayerTransactionTest.h" @@ -32,7 +33,7 @@ using android::hardware::graphics::common::V1_1::BufferUsage; ::testing::Environment* const binderEnv = ::testing::AddGlobalTestEnvironment(new BinderEnvironment()); -class MultiDisplayLayerBoundsTest : public LayerTransactionTest { +class MultiDisplayTest : public LayerTransactionTest { protected: virtual void SetUp() { LayerTransactionTest::SetUp(); @@ -45,11 +46,17 @@ protected: SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState); SurfaceComposerClient::getActiveDisplayMode(mMainDisplay, &mMainDisplayMode); - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&mProducer, &consumer); - consumer->setConsumerName(String8("Virtual disp consumer")); - consumer->setDefaultBufferSize(mMainDisplayMode.resolution.getWidth(), - mMainDisplayMode.resolution.getHeight()); + BufferQueue::createBufferQueue(&mProducer, &mConsumer); + mConsumer->setConsumerName(String8("Virtual disp consumer (MultiDisplayLayerBounds)")); + mConsumer->setDefaultBufferSize(mMainDisplayMode.resolution.getWidth(), + mMainDisplayMode.resolution.getHeight()); + + class StubConsumerListener : public BnConsumerListener { + virtual void onFrameAvailable(const BufferItem&) override {} + virtual void onBuffersReleased() override {} + virtual void onSidebandStreamChanged() override {} + }; + mConsumer->consumerConnect(sp<StubConsumerListener>::make(), true); } virtual void TearDown() { @@ -92,12 +99,13 @@ protected: sp<IBinder> mMainDisplay; PhysicalDisplayId mMainDisplayId; sp<IBinder> mVirtualDisplay; + sp<IGraphicBufferConsumer> mConsumer; sp<IGraphicBufferProducer> mProducer; sp<SurfaceControl> mColorLayer; Color mExpectedColor = {63, 63, 195, 255}; }; -TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) { +TEST_F(MultiDisplayTest, RenderLayerInVirtualDisplay) { constexpr ui::LayerStack kLayerStack{1u}; createDisplay(mMainDisplayState.layerStackSpaceRect, kLayerStack); createColorLayer(kLayerStack); @@ -116,7 +124,7 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) { sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 255}); } -TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { +TEST_F(MultiDisplayTest, RenderLayerInMirroredVirtualDisplay) { // Create a display and set its layer stack to the main display's layer stack so // the contents of the main display are mirrored on to the virtual display. @@ -142,7 +150,7 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255}); } -TEST_F(MultiDisplayLayerBoundsTest, RenderLayerWithPromisedFenceInMirroredVirtualDisplay) { +TEST_F(MultiDisplayTest, RenderLayerWithPromisedFenceInMirroredVirtualDisplay) { // Create a display and use a unique layerstack ID for mirrorDisplay() so // the contents of the main display are mirrored on to the virtual display. @@ -173,6 +181,51 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerWithPromisedFenceInMirroredVirtua sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255}); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +TEST_F(MultiDisplayTest, rejectDuplicateLayerStacks) { + if (!FlagManager::getInstance().reject_dupe_layerstacks()) return; + + // Setup + sp<CpuConsumer> cpuConsumer1 = sp<CpuConsumer>::make(static_cast<size_t>(1)); + cpuConsumer1->setName(String8("consumer 1")); + cpuConsumer1->setDefaultBufferSize(100, 100); + sp<IGraphicBufferProducer> cpuProducer1 = + cpuConsumer1->getSurface()->getIGraphicBufferProducer(); + CpuConsumer::LockedBuffer buffer1; + + sp<CpuConsumer> cpuConsumer2 = sp<CpuConsumer>::make(static_cast<size_t>(1)); + cpuConsumer2->setName(String8("consumer 2")); + cpuConsumer2->setDefaultBufferSize(100, 100); + sp<IGraphicBufferProducer> cpuProducer2 = + cpuConsumer2->getSurface()->getIGraphicBufferProducer(); + CpuConsumer::LockedBuffer buffer2; + + SurfaceComposerClient::Transaction t; + constexpr ui::LayerStack layerStack = {123u}; + createColorLayer(layerStack); + + static const std::string kDisplayName1("VirtualDisplay1 - rejectDuplicateLayerStacks"); + sp<IBinder> virtualDisplay1 = + SurfaceComposerClient::createVirtualDisplay(kDisplayName1, false /*isSecure*/); + + t.setDisplaySurface(virtualDisplay1, cpuProducer1); + t.setDisplayLayerStack(virtualDisplay1, layerStack); + t.apply(true); + + static const std::string kDisplayName2("VirtualDisplay2 - rejectDuplicateLayerStacks"); + sp<IBinder> virtualDisplay2 = + SurfaceComposerClient::createVirtualDisplay(kDisplayName2, false /*isSecure*/); + + t.setDisplaySurface(virtualDisplay2, cpuProducer2); + t.setDisplayLayerStack(virtualDisplay2, layerStack); + t.apply(true); + + // The second consumer will not be able to lock a buffer because + // the duplicate layer stack should be rejected. + ASSERT_EQ(NO_ERROR, cpuConsumer1->lockNextBuffer(&buffer1)); + ASSERT_NE(NO_ERROR, cpuConsumer2->lockNextBuffer(&buffer2)); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h index bf5957a89a..c95c875746 100644 --- a/services/surfaceflinger/tests/TransactionTestHarnesses.h +++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h @@ -58,7 +58,7 @@ public: GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_SW_READ_OFTEN); sp<BufferListener> listener = sp<BufferListener>::make(this); itemConsumer->setFrameAvailableListener(listener); - itemConsumer->setName(String8("Virtual disp consumer")); + itemConsumer->setName(String8("Virtual disp consumer (TransactionTest)")); itemConsumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); #else sp<IGraphicBufferProducer> producer; @@ -66,7 +66,7 @@ public: sp<BufferItemConsumer> itemConsumer; BufferQueue::createBufferQueue(&producer, &consumer); - consumer->setConsumerName(String8("Virtual disp consumer")); + consumer->setConsumerName(String8("Virtual disp consumer (TransactionTest)")); consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight()); itemConsumer = sp<BufferItemConsumer>::make(consumer, diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp index d69378cec2..1108c7fe56 100644 --- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp +++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp @@ -29,14 +29,14 @@ protected: void SetUp() override { #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) mGLConsumer = sp<GLConsumer>::make(GLConsumer::TEXTURE_EXTERNAL, true, false, false); - mGLConsumer->setName(String8("Virtual disp consumer")); + mGLConsumer->setName(String8("Virtual disp consumer (VirtualDisplayTest)")); mGLConsumer->setDefaultBufferSize(100, 100); mProducer = mGLConsumer->getSurface()->getIGraphicBufferProducer(); #else sp<IGraphicBufferConsumer> consumer; BufferQueue::createBufferQueue(&mProducer, &consumer); - consumer->setConsumerName(String8("Virtual disp consumer")); + consumer->setConsumerName(String8("Virtual disp consumer (VirtualDisplayTest)")); consumer->setDefaultBufferSize(100, 100); mGLConsumer = sp<GLConsumer>::make(consumer, GLConsumer::TEXTURE_EXTERNAL, true, false); diff --git a/services/surfaceflinger/tests/unittests/ActivePictureTrackerTest.cpp b/services/surfaceflinger/tests/unittests/ActivePictureTrackerTest.cpp new file mode 100644 index 0000000000..8011309519 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/ActivePictureTrackerTest.cpp @@ -0,0 +1,482 @@ +/* + * Copyright 2024 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 <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <android/gui/ActivePicture.h> +#include <android/gui/IActivePictureListener.h> +#include <compositionengine/mock/CompositionEngine.h> +#include <mock/DisplayHardware/MockComposer.h> +#include <mock/MockLayer.h> +#include <renderengine/mock/RenderEngine.h> + +#include "ActivePictureTracker.h" +#include "LayerFE.h" +#include "TestableSurfaceFlinger.h" + +namespace android { + +using android::compositionengine::LayerFECompositionState; +using android::gui::ActivePicture; +using android::gui::IActivePictureListener; +using android::mock::MockLayer; +using surfaceflinger::frontend::LayerSnapshot; +using testing::_; +using testing::NiceMock; +using testing::Return; +using testing::SizeIs; +using testing::StrictMock; + +class TestableLayerFE : public LayerFE { +public: + TestableLayerFE() : LayerFE("TestableLayerFE"), snapshot(*(new LayerSnapshot)) { + mSnapshot = std::unique_ptr<LayerSnapshot>(&snapshot); + } + + LayerSnapshot& snapshot; +}; + +class MockActivePictureListener : public gui::BnActivePictureListener { +public: + operator ActivePictureTracker::Listeners const() { + return {sp<IActivePictureListener>::fromExisting(this)}; + } + + MOCK_METHOD(binder::Status, onActivePicturesChanged, (const std::vector<ActivePicture>&), + (override)); +}; + +class ActivePictureTrackerTest : public testing::Test { +protected: + const static ActivePictureTracker::Listeners NO_LISTENERS; + + SurfaceFlinger* flinger() { + if (!mFlingerSetup) { + mFlinger.setupMockScheduler(); + mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); + mFlinger.setupRenderEngine(std::make_unique<renderengine::mock::RenderEngine>()); + mFlingerSetup = true; + } + return mFlinger.flinger(); + } + + sp<NiceMock<MockLayer>> createMockLayer(int layerId, int ownerUid) { + auto layer = sp<NiceMock<MockLayer>>::make(flinger(), layerId); + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(ownerUid))); + return layer; + } + + sp<StrictMock<MockActivePictureListener>> createMockListener() { + return sp<StrictMock<MockActivePictureListener>>::make(); + } + + ActivePictureTracker::Listeners mListenersToAdd; + ActivePictureTracker::Listeners mListenersToRemove; + +private: + TestableSurfaceFlinger mFlinger; + bool mFlingerSetup = false; +}; + +const ActivePictureTracker::Listeners ActivePictureTrackerTest::NO_LISTENERS; + +// Hack to workaround initializer lists not working for parcelables because parcelables inherit from +// Parcelable, which has a virtual destructor. +auto UnorderedElementsAre(std::initializer_list<std::tuple<int32_t, int32_t, int64_t>> tuples) { + std::vector<ActivePicture> activePictures; + for (auto tuple : tuples) { + ActivePicture ap; + ap.layerId = std::get<0>(tuple); + ap.ownerUid = std::get<1>(tuple); + ap.pictureProfileId = std::get<2>(tuple); + activePictures.push_back(ap); + } + return testing::UnorderedElementsAreArray(activePictures); +} + +// Parcelables don't define this for matchers, which is unfortunate +void PrintTo(const ActivePicture& activePicture, std::ostream* os) { + *os << activePicture.toString(); +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_called) { + ActivePictureTracker tracker; + auto listener = createMockListener(); + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_withListenerAlreadyAdded_notCalled) { + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + EXPECT_CALL(*listener, onActivePicturesChanged(_)).Times(0); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_withUncommittedProfile_calledWithNone) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } + { + auto listener = createMockListener(); + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_withCommittedProfile_calledWithActivePicture) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + auto listener = createMockListener(); + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileAdded_calledWithActivePicture) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenContinuesUsingProfile_notCalled) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)).Times(0); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileIsRemoved_calledWithNoActivePictures) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileIsNotCommitted_calledWithNoActivePictures) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileChanges_calledWithDifferentProfile) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenMultipleCommittedProfiles_calledWithMultipleActivePictures) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 20); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(2))) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenNonCommittedProfileChanges_notCalled) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 20); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)).Times(0); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenDifferentLayerUsesSameProfile_called) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 20); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 2}, {200, 20, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenSameUidDifferentLayerUsesSameProfile_called) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 10); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 10, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 2}, {200, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenNewLayerUsesSameProfile_called) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + + auto layer2 = createMockLayer(200, 10); + TestableLayerFE layerFE2; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp b/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp deleted file mode 100644 index b926d2f4da..0000000000 --- a/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2024 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 <gmock/gmock.h> -#include <gtest/gtest.h> - -#include <android/gui/ActivePicture.h> -#include <android/gui/IActivePictureListener.h> -#include <compositionengine/mock/CompositionEngine.h> -#include <mock/DisplayHardware/MockComposer.h> -#include <mock/MockLayer.h> -#include <renderengine/mock/RenderEngine.h> - -#include "ActivePictureUpdater.h" -#include "LayerFE.h" -#include "TestableSurfaceFlinger.h" - -namespace android { - -using android::compositionengine::LayerFECompositionState; -using android::gui::ActivePicture; -using android::gui::IActivePictureListener; -using android::mock::MockLayer; -using surfaceflinger::frontend::LayerSnapshot; -using testing::_; -using testing::NiceMock; -using testing::Return; - -class TestableLayerFE : public LayerFE { -public: - TestableLayerFE() : LayerFE("TestableLayerFE"), snapshot(*(new LayerSnapshot)) { - mSnapshot = std::unique_ptr<LayerSnapshot>(&snapshot); - } - - LayerSnapshot& snapshot; -}; - -class ActivePictureUpdaterTest : public testing::Test { -protected: - SurfaceFlinger* flinger() { - if (!mFlingerSetup) { - mFlinger.setupMockScheduler(); - mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); - mFlinger.setupRenderEngine(std::make_unique<renderengine::mock::RenderEngine>()); - mFlingerSetup = true; - } - return mFlinger.flinger(); - } - -private: - TestableSurfaceFlinger mFlinger; - bool mFlingerSetup = false; -}; - -// Hack to workaround initializer lists not working for parcelables because parcelables inherit from -// Parcelable, which has a virtual destructor. -auto UnorderedElementsAre(std::initializer_list<std::tuple<int32_t, int32_t, int64_t>> tuples) { - std::vector<ActivePicture> activePictures; - for (auto tuple : tuples) { - ActivePicture ap; - ap.layerId = std::get<0>(tuple); - ap.ownerUid = std::get<1>(tuple); - ap.pictureProfileId = std::get<2>(tuple); - activePictures.push_back(ap); - } - return testing::UnorderedElementsAreArray(activePictures); -} - -// Parcelables don't define this for matchers, which is unfortunate -void PrintTo(const ActivePicture& activePicture, std::ostream* os) { - *os << activePicture.toString(); -} - -TEST_F(ActivePictureUpdaterTest, notCalledWithNoProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenLayerStartsUsingProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } -} - -TEST_F(ActivePictureUpdaterTest, notCalledWhenLayerContinuesUsingProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenLayerStopsUsingProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({})); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenLayerChangesProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 2}})); - } -} - -TEST_F(ActivePictureUpdaterTest, notCalledWhenUncommittedLayerChangesProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenDifferentLayerUsesSameProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); - } - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 2}, {200, 20, 1}})); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenSameUidUsesSameProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 1}, {200, 10, 2}})); - } - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 2}, {200, 10, 1}})); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenNewLayerUsesSameProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 1}, {200, 10, 1}})); - } -} - -} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 6af51435c3..42259af7b0 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -103,6 +103,7 @@ cc_defaults { "librenderengine_deps", "libsurfaceflinger_common_test_deps", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], static_libs: [ "android.hardware.common-V2-ndk", diff --git a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h index b517ff02ad..c858d9a477 100644 --- a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h +++ b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h @@ -54,8 +54,8 @@ struct CommitAndCompositeTest : testing::Test { compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(), std::move(compostionEngineDisplayArgs)); mDisplay = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, - ui::DisplayConnectionType::Internal, HWC_DISPLAY, - kIsPrimary) + ui::DisplayConnectionType::Internal, + DEFAULT_DISPLAY_PORT, HWC_DISPLAY, kIsPrimary) .setDisplaySurface(mDisplaySurface) .setNativeWindow(mNativeWindow) .setPowerMode(hal::PowerMode::ON) @@ -68,7 +68,9 @@ struct CommitAndCompositeTest : testing::Test { using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; static constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID; - static constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); + static constexpr uint8_t DEFAULT_DISPLAY_PORT = 42u; + static constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = + PhysicalDisplayId::fromPort(DEFAULT_DISPLAY_PORT); static constexpr int DEFAULT_DISPLAY_WIDTH = 1920; static constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 860ad2e013..71cafbfd64 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -76,7 +76,8 @@ constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DIS constexpr hal::HWLayerId HWC_LAYER = 5000; constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0); -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); +constexpr uint8_t DEFAULT_DISPLAY_PORT = 42u; +constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(DEFAULT_DISPLAY_PORT); constexpr int DEFAULT_DISPLAY_WIDTH = 1920; constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; @@ -276,7 +277,8 @@ struct BaseDisplayVariant { test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - kDisplayConnectionType, HWC_DISPLAY, kIsPrimary) + kDisplayConnectionType, DEFAULT_DISPLAY_PORT, HWC_DISPLAY, + kIsPrimary) .setDisplaySurface(test->mDisplaySurface) .setNativeWindow(test->mNativeWindow) .setSecure(Derived::IS_SECURE) diff --git a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp index 29a1fab5ff..c6cbe52c4a 100644 --- a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp @@ -71,7 +71,7 @@ public: ASSERT_TRUE(infoOpt); mDisplayId = infoOpt->id; - mDisplaySnapshotOpt.emplace(mDisplayId, ui::DisplayConnectionType::Internal, + mDisplaySnapshotOpt.emplace(mDisplayId, infoOpt->port, ui::DisplayConnectionType::Internal, makeModes(kMode60, kMode90, kMode120), ui::ColorModes{}, std::nullopt); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index fa976c8091..6e231aa7f4 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -231,6 +231,16 @@ struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> { static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID; }; +template <typename> +struct PortGetter { + static constexpr std::optional<uint8_t> value; +}; + +template <typename PhysicalDisplay> +struct PortGetter<PhysicalDisplayIdType<PhysicalDisplay>> { + static constexpr std::optional<uint8_t> value = PhysicalDisplay::PORT; +}; + // DisplayIdType can be: // 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC. // 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC. @@ -241,6 +251,7 @@ struct DisplayVariant { using DISPLAY_ID = DisplayIdGetter<DisplayIdType>; using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>; using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>; + using PORT = PortGetter<DisplayIdType>; static constexpr int WIDTH = width; static constexpr int HEIGHT = height; @@ -277,6 +288,7 @@ struct DisplayVariant { TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, CONNECTION_TYPE::value, + PORT::value, HWC_DISPLAY_ID_OPT::value, static_cast<bool>(PRIMARY)); @@ -558,6 +570,10 @@ using OuterDisplayNonSecureVariant = /*hasIdentificationData=*/true, kNonSecure>, 1080, 2092>; +using ExternalDisplayWithIdentificationVariant = + PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External, + /*hasIdentificationData=*/true, kNonSecure>, + 1920, 1280>; using ExternalDisplayVariant = PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External, /*hasIdentificationData=*/false, kSecure>, diff --git a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h index 744c53637a..5f7a9f2422 100644 --- a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h +++ b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h @@ -24,12 +24,15 @@ namespace android { +static constexpr uint8_t kDefaultPort = 255u; + using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; using android::adpf::mock::PowerAdvisor; using android::hardware::graphics::composer::hal::HWDisplayId; struct FakeDisplayInjectorArgs { - PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(255u); + PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(kDefaultPort); + uint8_t port = kDefaultPort; HWDisplayId hwcDisplayId = 0; bool isPrimary = true; }; @@ -73,7 +76,7 @@ public: .build()); auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, - ui::DisplayConnectionType::Internal, + ui::DisplayConnectionType::Internal, args.port, args.hwcDisplayId, args.isPrimary); injector.setNativeWindow(mNativeWindow); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index b0dd5c21f8..a506873d4c 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -126,8 +126,9 @@ public: static constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID; static constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1; - - static constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u); + static constexpr uint8_t kOuterDisplayPort = 254u; + static constexpr PhysicalDisplayId kOuterDisplayId = + PhysicalDisplayId::fromPort(kOuterDisplayPort); auto injectOuterDisplay() { // For the inner display, this is handled by setupHwcHotplugCallExpectations. @@ -149,6 +150,7 @@ public: kModeId120); }, {.displayId = kOuterDisplayId, + .port = kOuterDisplayPort, .hwcDisplayId = kOuterDisplayHwcId, .isPrimary = kIsPrimary}); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp index aef467ab9d..4e7a1742fd 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -59,6 +59,137 @@ TEST_F(HotplugTest, schedulesFrameToCommitDisplayTransaction) { EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); } +TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithIdentificationData) { + // Configure a primary display with identification data. + using PrimaryDisplay = InnerDisplayVariant; + PrimaryDisplay::setupHwcHotplugCallExpectations(this); + PrimaryDisplay::setupHwcGetActiveConfigCallExpectations(this); + PrimaryDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(PrimaryDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + // A single commit should be scheduled. + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1); + + mFlinger.configure(); + + // Configure an external display with identification info. + using ExternalDisplay = ExternalDisplayWithIdentificationVariant; + ExternalDisplay::setupHwcHotplugCallExpectations(this); + ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this); + ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + mFlinger.configure(); + + EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID)); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get())); + const auto primaryDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(primaryDisplayIdOpt.has_value()); + const auto primaryPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(primaryDisplayIdOpt.value()); + ASSERT_TRUE(primaryPhysicalDisplayOpt.has_value()); + const auto primaryDisplaySnapshotRef = primaryPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(PrimaryDisplay::DISPLAY_ID::get(), primaryDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(PrimaryDisplay::PORT::value, primaryDisplaySnapshotRef.get().port()); + EXPECT_EQ(PrimaryDisplay::CONNECTION_TYPE::value, + primaryDisplaySnapshotRef.get().connectionType()); + + EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(ExternalDisplay::DISPLAY_ID::get())); + const auto externalDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(ExternalDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(externalDisplayIdOpt.has_value()); + const auto externalPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(externalDisplayIdOpt.value()); + ASSERT_TRUE(externalPhysicalDisplayOpt.has_value()); + const auto externalDisplaySnapshotRef = externalPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(ExternalDisplay::DISPLAY_ID::get(), externalDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(ExternalDisplay::PORT::value, externalDisplaySnapshotRef.get().port()); + EXPECT_EQ(ExternalDisplay::CONNECTION_TYPE::value, + externalDisplaySnapshotRef.get().connectionType()); +} + +TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithoutIdentificationData) { + // Configure a primary display without identification data. + using PrimaryDisplay = PrimaryDisplayVariant; + PrimaryDisplay::setupHwcHotplugCallExpectations(this); + PrimaryDisplay::setupHwcGetActiveConfigCallExpectations(this); + PrimaryDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(PrimaryDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + // A single commit should be scheduled. + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1); + + mFlinger.configure(); + + // Configure an external display with identification info. + using ExternalDisplay = ExternalDisplayWithIdentificationVariant; + ExternalDisplay::setupHwcHotplugCallExpectations(this); + ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this); + ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + mFlinger.configure(); + + // Both ID and port are expected to be equal to 0 for primary internal display due to no + // identification data. + constexpr uint8_t primaryInternalDisplayPort = 0u; + constexpr PhysicalDisplayId primaryInternalDisplayId = + PhysicalDisplayId::fromPort(primaryInternalDisplayPort); + EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID)); + ASSERT_EQ(primaryInternalDisplayId, PrimaryDisplay::DISPLAY_ID::get()); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get())); + const auto primaryDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(primaryDisplayIdOpt.has_value()); + const auto primaryPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(primaryDisplayIdOpt.value()); + ASSERT_TRUE(primaryPhysicalDisplayOpt.has_value()); + const auto primaryDisplaySnapshotRef = primaryPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(primaryInternalDisplayId, primaryDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(primaryInternalDisplayPort, primaryDisplaySnapshotRef.get().port()); + EXPECT_EQ(PrimaryDisplay::CONNECTION_TYPE::value, + primaryDisplaySnapshotRef.get().connectionType()); + + // Even though the external display has identification data available, the lack of data for the + // internal display has set of the legacy multi-display mode in SF and therefore the external + // display's identification data will be ignored. + // Both ID and port are expected to be equal to 1 for external internal display. + constexpr uint8_t externalDisplayPort = 1u; + constexpr PhysicalDisplayId externalDisplayId = + PhysicalDisplayId::fromPort(externalDisplayPort); + EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(externalDisplayId)); + const auto externalDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(ExternalDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(externalDisplayIdOpt.has_value()); + const auto externalPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(externalDisplayIdOpt.value()); + ASSERT_TRUE(externalPhysicalDisplayOpt.has_value()); + const auto externalDisplaySnapshotRef = externalPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(externalDisplayId, externalDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(externalDisplayPort, externalDisplaySnapshotRef.get().port()); + EXPECT_EQ(ExternalDisplay::CONNECTION_TYPE::value, + externalDisplaySnapshotRef.get().connectionType()); +} + TEST_F(HotplugTest, ignoresDuplicateDisconnection) { // Inject a primary display. PrimaryDisplayVariant::injectHwcDisplay(this); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index 352000ef9a..6951eaf093 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -239,6 +239,8 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); + const auto port = Case::Display::PORT::value; + ASSERT_TRUE(port); mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId, std::nullopt); DisplayModePtr activeMode = DisplayMode::Builder(Case::Display::HWC_ACTIVE_CONFIG_ID) .setResolution(Case::Display::RESOLUTION) @@ -258,7 +260,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { } const auto it = mFlinger.mutablePhysicalDisplays() - .emplace_or_replace(*displayId, displayToken, *displayId, + .emplace_or_replace(*displayId, displayToken, *displayId, *port, *kConnectionTypeOpt, makeModes(activeMode), std::move(colorModes), std::nullopt) .first; @@ -299,6 +301,13 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { mFlinger.mutableDisplayModeController() .getActiveMode(device->getPhysicalId()) .modePtr->getHwcId()); + + EXPECT_EQ(Case::Display::PORT::value, + mFlinger.physicalDisplays() + .get(device->getPhysicalId()) + .transform([](const display::PhysicalDisplay& display) { + return display.snapshot().port(); + })); } } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 7f0b7a6585..bd1382e851 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -947,11 +947,13 @@ public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, std::shared_ptr<compositionengine::Display> display, std::optional<ui::DisplayConnectionType> connectionType, + std::optional<uint8_t> port, std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary) : mFlinger(flinger), mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken, display), mConnectionType(connectionType), + mPort(port), mHwcDisplayId(hwcDisplayId) { mCreationArgs.isPrimary = isPrimary; mCreationArgs.initialPowerMode = hal::PowerMode::ON; @@ -1100,11 +1102,12 @@ public: .hwcDisplayId = *mHwcDisplayId, .activeMode = activeModeOpt->get()}; - const auto it = mFlinger.mutablePhysicalDisplays() - .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, - *mConnectionType, std::move(modes), - ui::ColorModes(), std::nullopt) - .first; + const auto it = + mFlinger.mutablePhysicalDisplays() + .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, *mPort, + *mConnectionType, std::move(modes), + ui::ColorModes(), std::nullopt) + .first; mFlinger.mutableDisplayModeController() .registerDisplay(*physicalId, it->second.snapshot(), @@ -1138,6 +1141,7 @@ public: DisplayModeId mActiveModeId; bool mSchedulerRegistration = true; const std::optional<ui::DisplayConnectionType> mConnectionType; + const std::optional<uint8_t> mPort; const std::optional<hal::HWDisplayId> mHwcDisplayId; }; diff --git a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h index 5c4512a2df..fd55597d7a 100644 --- a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h @@ -63,6 +63,8 @@ public: MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override)); MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override)); MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); + MOCK_METHOD(std::shared_ptr<SessionManager>, getSessionManager, (), (override)); + MOCK_METHOD(sp<IBinder>, getOrCreateSessionManagerForBinder, (uid_t uid), (override)); }; } // namespace android::adpf::mock diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc index 9b508aa5ce..3cb94050af 100644 --- a/vulkan/vkjson/vkjson.cc +++ b/vulkan/vkjson/vkjson.cc @@ -400,6 +400,78 @@ struct EnumTraits<VkShaderFloatControlsIndependence> { } }; +template <> +struct EnumTraits<VkPipelineRobustnessBufferBehavior> { + static bool exist(uint32_t e) { + switch (e) { + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DEVICE_DEFAULT: + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_DISABLED: + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS: + case VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_2: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkPipelineRobustnessImageBehavior> { + static bool exist(uint32_t e) { + switch (e) { + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DEVICE_DEFAULT: + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_DISABLED: + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS: + case VK_PIPELINE_ROBUSTNESS_IMAGE_BEHAVIOR_ROBUST_IMAGE_ACCESS_2: + return true; + } + return false; + } +}; + +template <> +struct EnumTraits<VkImageLayout> { + static bool exist(uint32_t e) { + switch (e) { + case VK_IMAGE_LAYOUT_UNDEFINED: + case VK_IMAGE_LAYOUT_GENERAL: + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + case VK_IMAGE_LAYOUT_PREINITIALIZED: + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + case VK_IMAGE_LAYOUT_VIDEO_DECODE_DST_KHR: + case VK_IMAGE_LAYOUT_VIDEO_DECODE_SRC_KHR: + case VK_IMAGE_LAYOUT_VIDEO_DECODE_DPB_KHR: + case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR: + case VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT: + case VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR: +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DST_KHR: +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_SRC_KHR: +#endif +#ifdef VK_ENABLE_BETA_EXTENSIONS + case VK_IMAGE_LAYOUT_VIDEO_ENCODE_DPB_KHR: +#endif + case VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT: + return true; + } + return false; + } +}; + // VkSparseImageFormatProperties template <typename Visitor> @@ -810,6 +882,68 @@ inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan13Features* features visitor->Visit("shaderIntegerDotProduct", &features->shaderIntegerDotProduct) && visitor->Visit("maintenance4", &features->maintenance4); } + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkJsonCore14* core) { + return + visitor->Visit("features", &core->features) && + visitor->Visit("properties", &core->properties); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan14Properties* properties) { + return + visitor->Visit("lineSubPixelPrecisionBits", &properties->lineSubPixelPrecisionBits) && + visitor->Visit("maxVertexAttribDivisor", &properties->maxVertexAttribDivisor) && + visitor->Visit("supportsNonZeroFirstInstance", &properties->supportsNonZeroFirstInstance) && + visitor->Visit("maxPushDescriptors", &properties->maxPushDescriptors) && + visitor->Visit("dynamicRenderingLocalReadDepthStencilAttachments", &properties->dynamicRenderingLocalReadDepthStencilAttachments) && + visitor->Visit("dynamicRenderingLocalReadMultisampledAttachments", &properties->dynamicRenderingLocalReadMultisampledAttachments) && + visitor->Visit("earlyFragmentMultisampleCoverageAfterSampleCounting", &properties->earlyFragmentMultisampleCoverageAfterSampleCounting) && + visitor->Visit("earlyFragmentSampleMaskTestBeforeSampleCounting", &properties->earlyFragmentSampleMaskTestBeforeSampleCounting) && + visitor->Visit("depthStencilSwizzleOneSupport", &properties->depthStencilSwizzleOneSupport) && + visitor->Visit("polygonModePointSize", &properties->polygonModePointSize) && + visitor->Visit("nonStrictSinglePixelWideLinesUseParallelogram", &properties->nonStrictSinglePixelWideLinesUseParallelogram) && + visitor->Visit("nonStrictWideLinesUseParallelogram", &properties->nonStrictWideLinesUseParallelogram) && + visitor->Visit("blockTexelViewCompatibleMultipleLayers", &properties->blockTexelViewCompatibleMultipleLayers) && + visitor->Visit("maxCombinedImageSamplerDescriptorCount", &properties->maxCombinedImageSamplerDescriptorCount) && + visitor->Visit("fragmentShadingRateClampCombinerInputs", &properties->fragmentShadingRateClampCombinerInputs) && + visitor->Visit("defaultRobustnessStorageBuffers", &properties->defaultRobustnessStorageBuffers) && + visitor->Visit("defaultRobustnessUniformBuffers", &properties->defaultRobustnessUniformBuffers) && + visitor->Visit("defaultRobustnessVertexInputs", &properties->defaultRobustnessVertexInputs) && + visitor->Visit("defaultRobustnessImages", &properties->defaultRobustnessImages) && + visitor->Visit("copySrcLayoutCount", &properties->copySrcLayoutCount) && + visitor->VisitArray("pCopySrcLayouts", properties->copySrcLayoutCount, &properties->pCopySrcLayouts) && + visitor->Visit("copyDstLayoutCount", &properties->copyDstLayoutCount) && + visitor->VisitArray("pCopyDstLayouts", properties->copyDstLayoutCount, &properties->pCopyDstLayouts) && + visitor->Visit("optimalTilingLayoutUUID", &properties->optimalTilingLayoutUUID) && + visitor->Visit("identicalMemoryTypeRequirements", &properties->identicalMemoryTypeRequirements); +} + +template <typename Visitor> +inline bool Iterate(Visitor* visitor, VkPhysicalDeviceVulkan14Features* features) { + return + visitor->Visit("globalPriorityQuery", &features->globalPriorityQuery) && + visitor->Visit("shaderSubgroupRotate", &features->shaderSubgroupRotate) && + visitor->Visit("shaderSubgroupRotateClustered", &features->shaderSubgroupRotateClustered) && + visitor->Visit("shaderFloatControls2", &features->shaderFloatControls2) && + visitor->Visit("shaderExpectAssume", &features->shaderExpectAssume) && + visitor->Visit("rectangularLines", &features->rectangularLines) && + visitor->Visit("bresenhamLines", &features->bresenhamLines) && + visitor->Visit("smoothLines", &features->smoothLines) && + visitor->Visit("stippledRectangularLines", &features->stippledRectangularLines) && + visitor->Visit("stippledBresenhamLines", &features->stippledBresenhamLines) && + visitor->Visit("stippledSmoothLines", &features->stippledSmoothLines) && + visitor->Visit("vertexAttributeInstanceRateDivisor", &features->vertexAttributeInstanceRateDivisor) && + visitor->Visit("vertexAttributeInstanceRateZeroDivisor", &features->vertexAttributeInstanceRateZeroDivisor) && + visitor->Visit("indexTypeUint8", &features->indexTypeUint8) && + visitor->Visit("dynamicRenderingLocalRead", &features->dynamicRenderingLocalRead) && + visitor->Visit("maintenance5", &features->maintenance5) && + visitor->Visit("maintenance6", &features->maintenance6) && + visitor->Visit("pipelineProtectedAccess", &features->pipelineProtectedAccess) && + visitor->Visit("pipelineRobustness", &features->pipelineRobustness) && + visitor->Visit("hostImageCopy", &features->hostImageCopy); +} // clang-format on template <typename Visitor> @@ -1051,7 +1185,7 @@ inline bool Iterate(Visitor* visitor, VkJsonDevice* device) { switch (device->properties.apiVersion ^ VK_API_VERSION_PATCH(device->properties.apiVersion)) { case VK_API_VERSION_1_4: - // TODO: real 1.4 support here + ret &= visitor->Visit("core14", &device->core14); FALLTHROUGH_INTENDED; case VK_API_VERSION_1_3: ret &= visitor->Visit("core13", &device->core13); @@ -1224,6 +1358,12 @@ class JsonWriterVisitor { return true; } + template <typename T> + bool VisitArray(const char* key, uint32_t count, const T *value) { + object_[key] = ArrayToJsonValue(count, *value); + return true; + } + Json::Value get_object() const { return object_; } private: @@ -1288,6 +1428,15 @@ inline bool AsValue(Json::Value* json_value, float* value) { return true; } +inline bool AsValue(Json::Value* json_value, VkImageLayout* t) { + uint32_t value = 0; + if (!AsValue(json_value, &value)) + return false; + if (!EnumTraits<VkImageLayout>::exist(value)) return false; + *t = static_cast<VkImageLayout>(value); + return true; +} + template <typename T> inline bool AsArray(Json::Value* json_value, uint32_t count, T* values) { if (json_value->type() != Json::arrayValue || json_value->size() != count) @@ -1398,6 +1547,20 @@ class JsonReaderVisitor { return false; } + template <typename T> + bool VisitArray(const char* key, uint32_t count, T *value) { + Json::Value json_value = (*object_)[key]; + if (!json_value) { + if (errors_) + *errors_ = std::string(key) + " missing."; + return false; + } + if (AsArray(&json_value, count, *value)) return true; + if (errors_) + *errors_ = std::string("Wrong type for ") + std::string(key) + "."; + return false; + } + private: Json::Value* object_; diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h index 88f6e7de53..28de680a99 100644 --- a/vulkan/vkjson/vkjson.h +++ b/vulkan/vkjson/vkjson.h @@ -84,6 +84,11 @@ struct VkJsonCore13 { VkPhysicalDeviceVulkan13Features features; }; +struct VkJsonCore14 { + VkPhysicalDeviceVulkan14Properties properties; + VkPhysicalDeviceVulkan14Features features; +}; + struct VkJsonDevice { VkJsonDevice() { memset(&properties, 0, sizeof(VkPhysicalDeviceProperties)); @@ -110,6 +115,7 @@ struct VkJsonDevice { sizeof(VkPhysicalDeviceShaderDrawParameterFeatures)); memset(&core12, 0, sizeof(VkJsonCore12)); memset(&core13, 0, sizeof(VkJsonCore13)); + memset(&core14, 0, sizeof(VkJsonCore14)); } VkPhysicalDeviceProperties properties; VkPhysicalDeviceFeatures features; @@ -139,6 +145,7 @@ struct VkJsonDevice { external_semaphore_properties; VkJsonCore12 core12; VkJsonCore13 core13; + VkJsonCore14 core14; }; struct VkJsonDeviceGroup { diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc index 0ffe7e0fdf..32bc50b5f8 100644 --- a/vulkan/vkjson/vkjson_instance.cc +++ b/vulkan/vkjson/vkjson_instance.cc @@ -292,6 +292,22 @@ VkJsonDevice VkJsonGetDevice(VkPhysicalDevice physical_device) { vkGetPhysicalDeviceFeatures2(physical_device, &features); } + if (device.properties.apiVersion >= VK_API_VERSION_1_4) { + device.core14.properties.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_PROPERTIES; + device.core14.properties.pNext = properties.pNext; + properties.pNext = &device.core14.properties; + + vkGetPhysicalDeviceProperties2(physical_device, &properties); + + device.core14.features.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_4_FEATURES; + device.core14.features.pNext = features.pNext; + features.pNext = &device.core14.features; + + vkGetPhysicalDeviceFeatures2(physical_device, &features); + } + return device; } |