From 9f034475d961892e4c10e6ff7ecee96e464be00c Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 28 Mar 2018 15:29:00 -0700 Subject: Add proper namespace to GraphicTypes. Renamed GraphicsTypes.h to GraphicTypes.h and added proper namespace to avoid naming conflict. BUG: 77156734 Test: Build and flash Change-Id: Ibd9f454b5b72d5f8c6d94a3869a60a1bf821f106 --- libs/gui/ISurfaceComposer.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 0244bb512e..e22bc708c9 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -43,6 +43,8 @@ namespace android { +using ui::ColorMode; + class BpSurfaceComposer : public BpInterface { public: -- cgit v1.2.3-59-g8ed1b From 2d41e42f85d5cac0a71c247d1ecfd882638d4030 Mon Sep 17 00:00:00 2001 From: Ana Krulec Date: Thu, 26 Jul 2018 12:07:43 -0700 Subject: Updating ISurfaceComposer to report errors Test: Passes SF tests. Change-Id: I878fb381bf95d7b362d1d213aea5471baac71fee --- libs/gui/ISurfaceComposer.cpp | 73 ++++++++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 25 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index e22bc708c9..7f9668fc2c 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -116,20 +116,20 @@ public: data.writeInt32(maxLayerZ); data.writeInt32(static_cast(useIdentityTransform)); data.writeInt32(static_cast(rotation)); - status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); - - if (err != NO_ERROR) { - return err; + status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); + if (result != NO_ERROR) { + ALOGE("captureScreen failed to transact: %d", result); + return result; } - - err = reply.readInt32(); - if (err != NO_ERROR) { - return err; + result = reply.readInt32(); + if (result != NO_ERROR) { + ALOGE("captureScreen failed to readInt32: %d", result); + return result; } *outBuffer = new GraphicBuffer(); reply.read(**outBuffer); - return err; + return result; } virtual status_t captureLayers(const sp& layerHandleBinder, @@ -141,21 +141,20 @@ public: data.write(sourceCrop); data.writeFloat(frameScale); data.writeBool(childrenOnly); - status_t err = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); - - if (err != NO_ERROR) { - return err; + status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_LAYERS, data, &reply); + if (result != NO_ERROR) { + ALOGE("captureLayers failed to transact: %d", result); + return result; } - - err = reply.readInt32(); - if (err != NO_ERROR) { - return err; + result = reply.readInt32(); + if (result != NO_ERROR) { + ALOGE("captureLayers failed to readInt32: %d", result); + return result; } - *outBuffer = new GraphicBuffer(); reply.read(**outBuffer); - return err; + return result; } virtual bool authenticateSurfaceTexture( @@ -344,10 +343,26 @@ public: virtual status_t setActiveConfig(const sp& display, int id) { Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - data.writeInt32(id); - remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply); + status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (result != NO_ERROR) { + ALOGE("setActiveConfig failed to writeInterfaceToken: %d", result); + return result; + } + result = data.writeStrongBinder(display); + if (result != NO_ERROR) { + ALOGE("setActiveConfig failed to writeStrongBinder: %d", result); + return result; + } + result = data.writeInt32(id); + if (result != NO_ERROR) { + ALOGE("setActiveConfig failed to writeInt32: %d", result); + return result; + } + result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_CONFIG, data, &reply); + if (result != NO_ERROR) { + ALOGE("setActiveConfig failed to transact: %d", result); + return result; + } return reply.readInt32(); } @@ -429,8 +444,16 @@ public: virtual status_t clearAnimationFrameStats() { Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply); + status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (result != NO_ERROR) { + ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result); + return result; + } + result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply); + if (result != NO_ERROR) { + ALOGE("clearAnimationFrameStats failed to transact: %d", result); + return result; + } return reply.readInt32(); } -- cgit v1.2.3-59-g8ed1b From cd3f9e92f6dd1d4dc0fbabe248ccbfe3c56c7cdf Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 21 Aug 2018 15:15:42 -0700 Subject: Add getDisplayViewport for screenrecord tool Bug: b/112869712 Test: adb shell screenrecord Change-Id: I9f3f99de1a5bafc5318b24484f1916d28dcdfaa7 --- libs/gui/ISurfaceComposer.cpp | 48 ++++++++++++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 4 +++ libs/gui/include/gui/ISurfaceComposer.h | 6 +++- libs/gui/include/gui/SurfaceComposerClient.h | 3 ++ libs/gui/tests/Surface_test.cpp | 3 ++ services/surfaceflinger/SurfaceFlinger.cpp | 16 ++++++++++ services/surfaceflinger/SurfaceFlinger.h | 1 + 7 files changed, 80 insertions(+), 1 deletion(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 7f9668fc2c..81f692d374 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -331,6 +331,34 @@ public: return result; } + virtual status_t getDisplayViewport(const sp& display, Rect* outViewport) { + Parcel data, reply; + status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (result != NO_ERROR) { + ALOGE("getDisplayViewport failed to writeInterfaceToken: %d", result); + return result; + } + result = data.writeStrongBinder(display); + if (result != NO_ERROR) { + ALOGE("getDisplayViewport failed to writeStrongBinder: %d", result); + return result; + } + result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_VIEWPORT, data, &reply); + if (result != NO_ERROR) { + ALOGE("getDisplayViewport failed to transact: %d", result); + return result; + } + result = reply.readInt32(); + if (result == NO_ERROR) { + result = reply.read(*outViewport); + if (result != NO_ERROR) { + ALOGE("getDisplayViewport failed to read: %d", result); + return result; + } + } + return result; + } + virtual int getActiveConfig(const sp& display) { Parcel data, reply; @@ -747,6 +775,26 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } + case GET_DISPLAY_VIEWPORT: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + Rect outViewport; + sp display = nullptr; + status_t result = data.readStrongBinder(&display); + if (result != NO_ERROR) { + ALOGE("getDisplayViewport failed to readStrongBinder: %d", result); + return result; + } + result = getDisplayViewport(display, &outViewport); + result = reply->writeInt32(result); + if (result == NO_ERROR) { + result = reply->write(outViewport); + if (result != NO_ERROR) { + ALOGE("getDisplayViewport failed to write: %d", result); + return result; + } + } + return NO_ERROR; + } case GET_ACTIVE_CONFIG: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 17cff546e0..6518596caf 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -842,6 +842,10 @@ status_t SurfaceComposerClient::getDisplayInfo(const sp& display, return NO_ERROR; } +status_t SurfaceComposerClient::getDisplayViewport(const sp& display, Rect* outViewport) { + return ComposerService::getComposerService()->getDisplayViewport(display, outViewport); +} + int SurfaceComposerClient::getActiveConfig(const sp& display) { return ComposerService::getComposerService()->getActiveConfig(display); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 98ec33888d..b9158f128c 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -157,6 +157,9 @@ public: virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) = 0; + /* returns display viewport information of the given display */ + virtual status_t getDisplayViewport(const sp& display, Rect* outViewport) = 0; + /* indicates which of the configurations returned by getDisplayInfo is * currently active */ virtual int getActiveConfig(const sp& display) = 0; @@ -250,7 +253,8 @@ public: ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, GET_LAYER_DEBUG_INFO, - CREATE_SCOPED_CONNECTION + CREATE_SCOPED_CONNECTION, + GET_DISPLAY_VIEWPORT }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4907866d0f..9bd1131ec0 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -79,6 +79,9 @@ public: static status_t getDisplayInfo(const sp& display, DisplayInfo* info); + // Get the display viewport for the given display + static status_t getDisplayViewport(const sp& display, Rect* outViewport); + // Get the index of the current active configuration (relative to the list // returned by getDisplayInfo) static int getActiveConfig(const sp& display); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 3542aba83f..f22e7026e9 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -581,6 +581,9 @@ public: Vector* /*configs*/) override { return NO_ERROR; } status_t getDisplayStats(const sp& /*display*/, DisplayStatInfo* /*stats*/) override { return NO_ERROR; } + status_t getDisplayViewport(const sp& /*display*/, Rect* /*outViewport*/) override { + return NO_ERROR; + } int getActiveConfig(const sp& /*display*/) override { return 0; } status_t setActiveConfig(const sp& /*display*/, int /*id*/) override { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 337f89da67..31152c4915 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -876,6 +876,21 @@ status_t SurfaceFlinger::getDisplayStats(const sp&, DisplayStatInfo* st return NO_ERROR; } +status_t SurfaceFlinger::getDisplayViewport(const sp& display, Rect* outViewport) { + if (outViewport == nullptr || display.get() == nullptr) { + return BAD_VALUE; + } + + sp device(getDisplayDevice(display)); + if (device == nullptr) { + return BAD_VALUE; + } + + *outViewport = device->getViewport(); + + return NO_ERROR; +} + int SurfaceFlinger::getActiveConfig(const sp& displayToken) { const auto display = getDisplayDevice(displayToken); if (!display) { @@ -4483,6 +4498,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_DISPLAY_COLOR_MODES: case GET_DISPLAY_CONFIGS: case GET_DISPLAY_STATS: + case GET_DISPLAY_VIEWPORT: case GET_SUPPORTED_FRAME_TIMESTAMPS: // Calling setTransactionState is safe, because you need to have been // granted a reference to Client* and Handle* to do anything with it. diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f5d8eb408b..273ce22d71 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -431,6 +431,7 @@ private: virtual status_t captureLayers(const sp& parentHandle, sp* outBuffer, const Rect& sourceCrop, float frameScale, bool childrenOnly); virtual status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats); + virtual status_t getDisplayViewport(const sp& display, Rect* outViewport); virtual status_t getDisplayConfigs(const sp& displayToken, Vector* configs); virtual int getActiveConfig(const sp& displayToken); -- cgit v1.2.3-59-g8ed1b From 27de5df947ad88ea0a49e31680f80dc344c556bf Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Thu, 23 Aug 2018 17:04:51 -0700 Subject: Merge getDisplayViewport into DisplayInfo Bug: b/113041831 Test: build and adb shell screenrecord Change-Id: Id248d3ef6a6d90f51a5906e693d989b088e2bc99 --- libs/gui/ISurfaceComposer.cpp | 48 ---------------------------- libs/gui/SurfaceComposerClient.cpp | 4 --- libs/gui/include/gui/ISurfaceComposer.h | 6 +--- libs/gui/include/gui/SurfaceComposerClient.h | 3 -- libs/gui/tests/Surface_test.cpp | 3 -- libs/ui/include/ui/DisplayInfo.h | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 31 ++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 1 - 8 files changed, 16 insertions(+), 82 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 81f692d374..7f9668fc2c 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -331,34 +331,6 @@ public: return result; } - virtual status_t getDisplayViewport(const sp& display, Rect* outViewport) { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getDisplayViewport failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("getDisplayViewport failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_VIEWPORT, data, &reply); - if (result != NO_ERROR) { - ALOGE("getDisplayViewport failed to transact: %d", result); - return result; - } - result = reply.readInt32(); - if (result == NO_ERROR) { - result = reply.read(*outViewport); - if (result != NO_ERROR) { - ALOGE("getDisplayViewport failed to read: %d", result); - return result; - } - } - return result; - } - virtual int getActiveConfig(const sp& display) { Parcel data, reply; @@ -775,26 +747,6 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } - case GET_DISPLAY_VIEWPORT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - Rect outViewport; - sp display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getDisplayViewport failed to readStrongBinder: %d", result); - return result; - } - result = getDisplayViewport(display, &outViewport); - result = reply->writeInt32(result); - if (result == NO_ERROR) { - result = reply->write(outViewport); - if (result != NO_ERROR) { - ALOGE("getDisplayViewport failed to write: %d", result); - return result; - } - } - return NO_ERROR; - } case GET_ACTIVE_CONFIG: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 6518596caf..17cff546e0 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -842,10 +842,6 @@ status_t SurfaceComposerClient::getDisplayInfo(const sp& display, return NO_ERROR; } -status_t SurfaceComposerClient::getDisplayViewport(const sp& display, Rect* outViewport) { - return ComposerService::getComposerService()->getDisplayViewport(display, outViewport); -} - int SurfaceComposerClient::getActiveConfig(const sp& display) { return ComposerService::getComposerService()->getActiveConfig(display); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index b9158f128c..98ec33888d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -157,9 +157,6 @@ public: virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats) = 0; - /* returns display viewport information of the given display */ - virtual status_t getDisplayViewport(const sp& display, Rect* outViewport) = 0; - /* indicates which of the configurations returned by getDisplayInfo is * currently active */ virtual int getActiveConfig(const sp& display) = 0; @@ -253,8 +250,7 @@ public: ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, GET_LAYER_DEBUG_INFO, - CREATE_SCOPED_CONNECTION, - GET_DISPLAY_VIEWPORT + CREATE_SCOPED_CONNECTION }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 9bd1131ec0..4907866d0f 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -79,9 +79,6 @@ public: static status_t getDisplayInfo(const sp& display, DisplayInfo* info); - // Get the display viewport for the given display - static status_t getDisplayViewport(const sp& display, Rect* outViewport); - // Get the index of the current active configuration (relative to the list // returned by getDisplayInfo) static int getActiveConfig(const sp& display); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index f22e7026e9..3542aba83f 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -581,9 +581,6 @@ public: Vector* /*configs*/) override { return NO_ERROR; } status_t getDisplayStats(const sp& /*display*/, DisplayStatInfo* /*stats*/) override { return NO_ERROR; } - status_t getDisplayViewport(const sp& /*display*/, Rect* /*outViewport*/) override { - return NO_ERROR; - } int getActiveConfig(const sp& /*display*/) override { return 0; } status_t setActiveConfig(const sp& /*display*/, int /*id*/) override { diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h index 94caf6b9d3..8976d2d584 100644 --- a/libs/ui/include/ui/DisplayInfo.h +++ b/libs/ui/include/ui/DisplayInfo.h @@ -35,6 +35,8 @@ struct DisplayInfo { bool secure{false}; nsecs_t appVsyncOffset{0}; nsecs_t presentationDeadline{0}; + uint32_t viewportW{0}; + uint32_t viewportH{0}; }; /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */ diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index a7792893ef..6162b16322 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -805,6 +805,12 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, float xdpi = hwConfig->getDpiX(); float ydpi = hwConfig->getDpiY(); + info.w = hwConfig->getWidth(); + info.h = hwConfig->getHeight(); + // Default display viewport to display width and height + info.viewportW = info.w; + info.viewportH = info.h; + if (type == DisplayDevice::DISPLAY_PRIMARY) { // The density of the device is provided by a build property float density = Density::getBuildDensity() / 160.0f; @@ -824,6 +830,13 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, // TODO: this needs to go away (currently needed only by webkit) const auto display = getDefaultDisplayDeviceLocked(); info.orientation = display ? display->getOrientation() : 0; + + // This is for screenrecord + const Rect viewport = display->getViewport(); + if (viewport.isValid()) { + info.viewportW = uint32_t(viewport.getWidth()); + info.viewportH = uint32_t(viewport.getHeight()); + } } else { // TODO: where should this value come from? static const int TV_DENSITY = 213; @@ -831,8 +844,6 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, info.orientation = 0; } - info.w = hwConfig->getWidth(); - info.h = hwConfig->getHeight(); info.xdpi = xdpi; info.ydpi = ydpi; info.fps = 1e9 / hwConfig->getVsyncPeriod(); @@ -879,21 +890,6 @@ status_t SurfaceFlinger::getDisplayStats(const sp&, DisplayStatInfo* st return NO_ERROR; } -status_t SurfaceFlinger::getDisplayViewport(const sp& display, Rect* outViewport) { - if (outViewport == nullptr || display.get() == nullptr) { - return BAD_VALUE; - } - - sp device(getDisplayDevice(display)); - if (device == nullptr) { - return BAD_VALUE; - } - - *outViewport = device->getViewport(); - - return NO_ERROR; -} - int SurfaceFlinger::getActiveConfig(const sp& displayToken) { const auto display = getDisplayDevice(displayToken); if (!display) { @@ -4544,7 +4540,6 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_DISPLAY_COLOR_MODES: case GET_DISPLAY_CONFIGS: case GET_DISPLAY_STATS: - case GET_DISPLAY_VIEWPORT: case GET_SUPPORTED_FRAME_TIMESTAMPS: // Calling setTransactionState is safe, because you need to have been // granted a reference to Client* and Handle* to do anything with it. diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index ed9e212722..173ead8cd8 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -435,7 +435,6 @@ private: virtual status_t captureLayers(const sp& parentHandle, sp* outBuffer, const Rect& sourceCrop, float frameScale, bool childrenOnly); virtual status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats); - virtual status_t getDisplayViewport(const sp& display, Rect* outViewport); virtual status_t getDisplayConfigs(const sp& displayToken, Vector* configs); virtual int getActiveConfig(const sp& displayToken); -- cgit v1.2.3-59-g8ed1b From 0256f72d22cb4f8f73a86e3fbc916289b5feed43 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Fri, 31 Aug 2018 15:45:10 -0700 Subject: [SurfaceFlinger] Add getCompositionPreference APIs to SurfaceComposer. Previously we added APIs in ConfigStore to return the composition data space and pixel format that SurfaceFlinger would prefer for the device. This patch we plumb such information up to SurfaceComposer to prepare HWUI to use it to render. BUG: 113530681 Test: Build, flash, boot and verified the output in adb logcat. Change-Id: Ic96156e103af9f12febc98081179c2dc035a5139 --- libs/gui/ISurfaceComposer.cpp | 31 +++++++++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 5 ++++ libs/gui/include/gui/ISurfaceComposer.h | 6 ++++- libs/gui/include/gui/SurfaceComposerClient.h | 4 ++++ libs/gui/tests/Surface_test.cpp | 4 ++++ services/surfaceflinger/SurfaceFlinger.cpp | 34 ++++++++++++++++++++++++---- services/surfaceflinger/SurfaceFlinger.h | 8 +++++++ 7 files changed, 86 insertions(+), 6 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 7f9668fc2c..08fbfffd03 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -558,6 +558,25 @@ public: outLayers->clear(); return reply.readParcelableVector(outLayers); } + + virtual status_t getCompositionPreference(ui::Dataspace* dataSpace, + ui::PixelFormat* pixelFormat) const { + Parcel data, reply; + status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (error != NO_ERROR) { + return error; + } + error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply); + if (error != NO_ERROR) { + return error; + } + error = static_cast(reply.readInt32()); + if (error == NO_ERROR) { + *dataSpace = static_cast(reply.readInt32()); + *pixelFormat = static_cast(reply.readInt32()); + } + return error; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -881,6 +900,18 @@ status_t BnSurfaceComposer::onTransact( } return result; } + case GET_COMPOSITION_PREFERENCE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + ui::Dataspace dataSpace; + ui::PixelFormat pixelFormat; + status_t error = getCompositionPreference(&dataSpace, &pixelFormat); + reply->writeInt32(error); + if (error == NO_ERROR) { + reply->writeInt32(static_cast(dataSpace)); + reply->writeInt32(static_cast(pixelFormat)); + } + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7168de4f3b..4caadd13bd 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -854,6 +854,11 @@ void SurfaceComposerClient::setDisplayPowerMode(const sp& token, ComposerService::getComposerService()->setPowerMode(token, mode); } +status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace, + ui::PixelFormat* pixelFormat) { + return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat); +} + status_t SurfaceComposerClient::clearAnimationFrameStats() { return ComposerService::getComposerService()->clearAnimationFrameStats(); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 98ec33888d..8015095a9e 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -214,6 +214,9 @@ public: * Requires the ACCESS_SURFACE_FLINGER permission. */ virtual status_t getLayerDebugInfo(std::vector* outLayers) const = 0; + + virtual status_t getCompositionPreference(ui::Dataspace* dataSpace, + ui::PixelFormat* pixelFormat) const = 0; }; // ---------------------------------------------------------------------------- @@ -250,7 +253,8 @@ public: ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, GET_LAYER_DEBUG_INFO, - CREATE_SCOPED_CONNECTION + CREATE_SCOPED_CONNECTION, + GET_COMPOSITION_PREFERENCE, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index d83ba84228..662acc9acf 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -101,6 +101,10 @@ public: /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp& display, int mode); + // + static status_t getCompositionPreference(ui::Dataspace* dataSpace, + ui::PixelFormat* pixelFormat); + // ------------------------------------------------------------------------ // surface creation / destruction diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 3542aba83f..243f27f813 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -622,6 +622,10 @@ public: status_t getLayerDebugInfo(std::vector* /*layers*/) const override { return NO_ERROR; } + status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/, + ui::PixelFormat* /*outPixelFormat*/) const override { + return NO_ERROR; + } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d008f26bea..a5bd73a532 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -197,6 +197,8 @@ bool SurfaceFlinger::hasWideColorDisplay; int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault; bool SurfaceFlinger::useColorManagement; bool SurfaceFlinger::useContextPriority; +Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB; +ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888; std::string getHwcServiceName() { char value[PROPERTY_VALUE_MAX] = {}; @@ -323,13 +325,24 @@ SurfaceFlinger::SurfaceFlinger() : SurfaceFlinger(SkipInitialization) { hasWideColorDisplay = getBool(false); useColorManagement = - getBool(false); + getBool(false); + + auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService(); + if (surfaceFlingerConfigsServiceV1_2) { + surfaceFlingerConfigsServiceV1_2->getCompositionPreference( + [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) { + compositionDataSpace = tmpDataSpace; + compositionPixelFormat = tmpPixelFormat; + }); + } useContextPriority = getBool(true); V1_1::DisplayOrientation primaryDisplayOrientation = - getDisplayOrientation< V1_1::ISurfaceFlingerConfigs, &V1_1::ISurfaceFlingerConfigs::primaryDisplayOrientation>( + getDisplayOrientation( V1_1::DisplayOrientation::ORIENTATION_0); switch (primaryDisplayOrientation) { @@ -651,8 +664,11 @@ void SurfaceFlinger::init() { renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0); renderEngineFeature |= (useContextPriority ? renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0); - getBE().mRenderEngine = renderengine::impl::RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888, - renderEngineFeature); + + // TODO(b/77156734): We need to stop casting and use HAL types when possible. + getBE().mRenderEngine = + renderengine::impl::RenderEngine::create(static_cast(compositionPixelFormat), + renderEngineFeature); LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine"); LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, @@ -1170,6 +1186,13 @@ status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayer return NO_ERROR; } +status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace, + ui::PixelFormat* outPixelFormat) const { + *outDataSpace = compositionDataSpace; + *outPixelFormat = compositionPixelFormat; + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp SurfaceFlinger::createDisplayEventConnection( @@ -4824,7 +4847,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // granted a reference to Client* and Handle* to do anything with it. case SET_TRANSACTION_STATE: // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h - case CREATE_SCOPED_CONNECTION: { + case CREATE_SCOPED_CONNECTION: + case GET_COMPOSITION_PREFERENCE: { return OK; } case CAPTURE_LAYERS: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b20fe44688..72ede93dda 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -296,6 +296,12 @@ public: static bool useContextPriority; + // The data space and pixel format that SurfaceFlinger expects hardware composer + // to composite efficiently. Meaning under most scenarios, hardware composer + // will accept layers with the data space and pixel format. + static ui::Dataspace compositionDataSpace; + static ui::PixelFormat compositionPixelFormat; + static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; } @@ -454,6 +460,8 @@ private: virtual status_t enableVSyncInjections(bool enable); virtual status_t injectVSync(nsecs_t when); virtual status_t getLayerDebugInfo(std::vector* outLayers) const; + status_t getCompositionPreference(ui::Dataspace* outDataSpace, + ui::PixelFormat* outPixelFormat) const override; /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From 0e3479f854cc5b5d89a70011f035de4839cab017 Mon Sep 17 00:00:00 2001 From: chaviw Date: Mon, 10 Sep 2018 16:49:30 -0700 Subject: Remove minLayer and maxLayer from screenshot code. When taking a full display screenshot, there's no longer a need for min and max layer. Instead, the entire display will be screenshotted. If only some layers should be screenshotted, then use the captureLayers method instead. This was already the case for real code, but required some clean up in Transaction_test Test: Transaction_test Change-Id: I774357b284ca9e026097f79fb7146e4931fa629a --- libs/gui/ISurfaceComposer.cpp | 9 +- libs/gui/SurfaceComposerClient.cpp | 7 +- libs/gui/include/gui/ISurfaceComposer.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 3 +- libs/gui/tests/Surface_test.cpp | 5 +- services/surfaceflinger/SurfaceFlinger.cpp | 13 +- services/surfaceflinger/SurfaceFlinger.h | 7 +- services/surfaceflinger/tests/Credentials_test.cpp | 6 +- services/surfaceflinger/tests/Transaction_test.cpp | 222 +++++++++++---------- .../tests/unittests/CompositionTest.cpp | 4 +- .../tests/unittests/TestableSurfaceFlinger.h | 7 +- 11 files changed, 143 insertions(+), 143 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 08fbfffd03..f99bc5307c 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -104,16 +104,13 @@ public: virtual status_t captureScreen(const sp& display, sp* outBuffer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, - ISurfaceComposer::Rotation rotation) { + bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); data.write(sourceCrop); data.writeUint32(reqWidth); data.writeUint32(reqHeight); - data.writeInt32(minLayerZ); - data.writeInt32(maxLayerZ); data.writeInt32(static_cast(useIdentityTransform)); data.writeInt32(static_cast(rotation)); status_t result = remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply); @@ -653,13 +650,11 @@ status_t BnSurfaceComposer::onTransact( data.read(sourceCrop); uint32_t reqWidth = data.readUint32(); uint32_t reqHeight = data.readUint32(); - int32_t minLayerZ = data.readInt32(); - int32_t maxLayerZ = data.readInt32(); bool useIdentityTransform = static_cast(data.readInt32()); int32_t rotation = data.readInt32(); status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight, - minLayerZ, maxLayerZ, useIdentityTransform, + useIdentityTransform, static_cast(rotation)); reply->writeInt32(res); if (res == NO_ERROR) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 4caadd13bd..09ea0f601a 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -876,13 +876,12 @@ status_t SurfaceComposerClient::getHdrCapabilities(const sp& display, // ---------------------------------------------------------------------------- status_t ScreenshotClient::capture(const sp& display, Rect sourceCrop, uint32_t reqWidth, - uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation, + uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation, sp* outBuffer) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ, - maxLayerZ, useIdentityTransform, + status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, + useIdentityTransform, static_cast(rotation)); if (ret != NO_ERROR) { return ret; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 46103c4fb1..a55cfe04d9 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -193,8 +193,7 @@ public: */ virtual status_t captureScreen(const sp& display, sp* outBuffer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, - Rotation rotation = eRotateNone) = 0; + bool useIdentityTransform, Rotation rotation = eRotateNone) = 0; /** * Capture a subtree of the layer hierarchy, potentially ignoring the root node. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 662acc9acf..314b1182b4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -326,8 +326,7 @@ public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); static status_t capture(const sp& display, Rect sourceCrop, uint32_t reqWidth, - uint32_t reqHeight, int32_t minLayerZ, int32_t maxLayerZ, - bool useIdentityTransform, uint32_t rotation, + uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation, sp* outBuffer); static status_t captureLayers(const sp& layerHandle, Rect sourceCrop, float frameScale, sp* outBuffer); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 243f27f813..bc8089982c 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -135,7 +135,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { ISurfaceComposer::eDisplayIdMain)); sp outBuffer; ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), - 64, 64, 0, 0x7fffffff, false)); + 64, 64, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU)); @@ -166,7 +166,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), - 64, 64, 0, 0x7fffffff, false)); + 64, 64, false)); } TEST_F(SurfaceTest, ConcreteTypeIsSurface) { @@ -599,7 +599,6 @@ public: status_t captureScreen(const sp& /*display*/, sp* /*outBuffer*/, Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, - int32_t /*minLayerZ*/, int32_t /*maxLayerZ*/, bool /*useIdentityTransform*/, Rotation /*rotation*/) override { return NO_ERROR; } virtual status_t captureLayers(const sp& /*parentHandle*/, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f17710ef0d..f218664af7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5199,8 +5199,8 @@ private: status_t SurfaceFlinger::captureScreen(const sp& displayToken, sp* outBuffer, Rect sourceCrop, - uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ, - int32_t maxLayerZ, bool useIdentityTransform, + uint32_t reqWidth, uint32_t reqHeight, + bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { ATRACE_CALL(); @@ -5230,7 +5230,7 @@ status_t SurfaceFlinger::captureScreen(const sp& displayToken, DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, renderAreaRotation); auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this, - display, minLayerZ, maxLayerZ, std::placeholders::_1); + display, std::placeholders::_1); return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform); } @@ -5562,19 +5562,14 @@ void SurfaceFlinger::State::traverseInReverseZOrder(const LayerVector::Visitor& } void SurfaceFlinger::traverseLayersInDisplay(const sp& display, - int32_t minLayerZ, int32_t maxLayerZ, const LayerVector::Visitor& visitor) { // We loop through the first level of layers without traversing, - // as we need to interpret min/max layer Z in the top level Z space. + // as we need to determine which layers belong to the requested display. for (const auto& layer : mDrawingState.layersSortedByZ) { if (!layer->belongsToDisplay(display->getLayerStack(), false)) { continue; } - const Layer::State& state(layer->getDrawingState()); // relative layers are traversed in Layer::traverseInZOrder - if (state.zOrderRelativeOf != nullptr || state.z < minLayerZ || state.z > maxLayerZ) { - continue; - } layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { if (!layer->belongsToDisplay(display->getLayerStack(), false)) { return; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 00ee2c4dac..9eb572c8f8 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -439,8 +439,7 @@ private: ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp); virtual status_t captureScreen(const sp& displayToken, sp* outBuffer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform, - ISurfaceComposer::Rotation rotation); + bool useIdentityTransform, ISurfaceComposer::Rotation rotation); virtual status_t captureLayers(const sp& parentHandle, sp* outBuffer, const Rect& sourceCrop, float frameScale, bool childrenOnly); virtual status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats); @@ -599,8 +598,8 @@ private: TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer, bool useIdentityTransform, bool forSystem, int* outSyncFd); - void traverseLayersInDisplay(const sp& display, int32_t minLayerZ, - int32_t maxLayerZ, const LayerVector::Visitor& visitor); + void traverseLayersInDisplay(const sp& display, + const LayerVector::Visitor& visitor); sp mStartPropertySetThread = nullptr; diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 8e23eb8e61..9e762f0eb1 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -23,8 +23,6 @@ using Transaction = SurfaceComposerClient::Transaction; namespace { const String8 DISPLAY_NAME("Credentials Display Test"); const String8 SURFACE_NAME("Test Surface Name"); -const int32_t MIN_LAYER_Z = 0; -const int32_t MAX_LAYER_Z = std::numeric_limits::max(); const uint32_t ROTATION = 0; const float FRAME_SCALE = 1.0f; } // namespace @@ -269,8 +267,8 @@ TEST_F(CredentialsTest, CaptureTest) { sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); std::function condition = [=]() { sp outBuffer; - return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, - MIN_LAYER_Z, MAX_LAYER_Z, false, ROTATION, &outBuffer); + return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, false, + ROTATION, &outBuffer); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index ed1529b37b..3af98e5c9b 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -186,17 +186,15 @@ static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, // individual pixel values for testing purposes. class ScreenCapture : public RefBase { public: - static void captureScreen(sp* sc, int32_t minLayerZ = 0, - int32_t maxLayerZ = std::numeric_limits::max()) { + static void captureScreen(std::unique_ptr* sc) { sp sf(ComposerService::getComposerService()); sp display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); SurfaceComposerClient::Transaction().apply(true); sp outBuffer; ASSERT_EQ(NO_ERROR, - sf->captureScreen(display, &outBuffer, Rect(), 0, 0, minLayerZ, maxLayerZ, - false)); - *sc = new ScreenCapture(outBuffer); + sf->captureScreen(display, &outBuffer, Rect(), 0, 0, false)); + *sc = std::make_unique(outBuffer); } static void captureLayers(std::unique_ptr* sc, sp& parentHandle, @@ -318,6 +316,12 @@ protected: ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); } + virtual void TearDown() { + mBlackBgSurface = 0; + mClient->dispose(); + mClient = 0; + } + virtual sp createLayer(const char* name, uint32_t width, uint32_t height, uint32_t flags = 0) { auto layer = @@ -445,9 +449,9 @@ protected: Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply(); } - sp screenshot() { - sp screenshot; - ScreenCapture::captureScreen(&screenshot, mLayerZBase); + std::unique_ptr screenshot() { + std::unique_ptr screenshot; + ScreenCapture::captureScreen(&screenshot); return screenshot; } @@ -465,6 +469,7 @@ protected: void setSizeBasicHelper(uint32_t layerType); void setMatrixWithResizeHelper(uint32_t layerType); + sp mBlackBgSurface; private: void SetUpDisplay() { mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); @@ -482,13 +487,26 @@ private: mBufferPostDelay = int32_t(1e6 / info.fps) * 3; mDisplayLayerStack = 0; + + mBlackBgSurface = mClient->createSurface(String8("BaseSurface"), mDisplayWidth, + mDisplayHeight, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceColor); + // set layer stack (b/68888219) Transaction t; t.setDisplayLayerStack(mDisplay, mDisplayLayerStack); + t.setLayerStack(mBlackBgSurface, mDisplayLayerStack); + t.setColor(mBlackBgSurface, half3{0, 0, 0}); + t.setLayer(mBlackBgSurface, mLayerZBase); t.apply(); } - void waitForLayerBuffers() { usleep(mBufferPostDelay); } + void waitForLayerBuffers() { + // Request an empty transaction to get applied synchronously to ensure the buffer is + // latched. + Transaction().apply(true); + usleep(mBufferPostDelay); + } int32_t mBufferPostDelay; }; @@ -793,6 +811,9 @@ TEST_P(LayerTypeTransactionTest, SetZBasic) { } TEST_P(LayerTypeTransactionTest, SetZNegative) { + sp parent = + LayerTransactionTest::createLayer("Parent", mDisplayWidth, mDisplayHeight, + ISurfaceComposerClient::eFXSurfaceContainer); sp layerR; sp layerG; ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32)); @@ -800,20 +821,22 @@ TEST_P(LayerTypeTransactionTest, SetZNegative) { ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32)); + Transaction() + .reparent(layerR, parent->getHandle()) + .reparent(layerG, parent->getHandle()) + .apply(); Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply(); { SCOPED_TRACE("layerR"); - sp screenshot; - ScreenCapture::captureScreen(&screenshot, -2, -1); - screenshot->expectColor(Rect(0, 0, 32, 32), Color::RED); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); } Transaction().setLayer(layerR, -3).apply(); { SCOPED_TRACE("layerG"); - sp screenshot; - ScreenCapture::captureScreen(&screenshot, -3, -1); - screenshot->expectColor(Rect(0, 0, 32, 32), Color::GREEN); + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN); } } @@ -846,6 +869,9 @@ TEST_P(LayerTypeTransactionTest, SetRelativeZBasic) { } TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) { + sp parent = + LayerTransactionTest::createLayer("Parent", mDisplayWidth, mDisplayHeight, + ISurfaceComposerClient::eFXSurfaceContainer); sp layerR; sp layerG; sp layerB; @@ -856,12 +882,17 @@ TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) { ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32)); ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32)); + Transaction() + .reparent(layerB, parent->getHandle()) + .apply(); + // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2 Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply(); - sp screenshot; + std::unique_ptr screenshot; // only layerB is in this range - ScreenCapture::captureScreen(&screenshot, -2, -1); + sp parentHandle = parent->getHandle(); + ScreenCapture::captureLayers(&screenshot, parentHandle); screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); } @@ -1006,13 +1037,11 @@ TEST_P(LayerTypeTransactionTest, SetFlagsSecure) { .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure) .apply(true); ASSERT_EQ(PERMISSION_DENIED, - composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, mLayerZBase, mLayerZBase, - false)); + composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false)); Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true); ASSERT_EQ(NO_ERROR, - composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, mLayerZBase, mLayerZBase, - false)); + composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false)); } TEST_F(LayerTransactionTest, SetTransparentRegionHintBasic_BufferQueue) { @@ -2038,8 +2067,8 @@ TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) { class LayerUpdateTest : public LayerTransactionTest { protected: virtual void SetUp() { - mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + LayerTransactionTest::SetUp(); + ASSERT_EQ(NO_ERROR, mClient->initCheck()); sp display( SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); @@ -2050,24 +2079,22 @@ protected: ssize_t displayHeight = info.h; // Background surface - mBGSurfaceControl = - mComposerClient->createSurface(String8("BG Test Surface"), displayWidth, - displayHeight, PIXEL_FORMAT_RGBA_8888, 0); + mBGSurfaceControl = createLayer(String8("BG Test Surface"), displayWidth, + displayHeight, 0); ASSERT_TRUE(mBGSurfaceControl != nullptr); ASSERT_TRUE(mBGSurfaceControl->isValid()); fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195); // Foreground surface - mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64, - PIXEL_FORMAT_RGBA_8888, 0); + mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0); + ASSERT_TRUE(mFGSurfaceControl != nullptr); ASSERT_TRUE(mFGSurfaceControl->isValid()); fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63); // Synchronization surface - mSyncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1, - PIXEL_FORMAT_RGBA_8888, 0); + mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0); ASSERT_TRUE(mSyncSurfaceControl != nullptr); ASSERT_TRUE(mSyncSurfaceControl->isValid()); @@ -2089,11 +2116,10 @@ protected: } virtual void TearDown() { - mComposerClient->dispose(); + LayerTransactionTest::TearDown(); mBGSurfaceControl = 0; mFGSurfaceControl = 0; mSyncSurfaceControl = 0; - mComposerClient = 0; } void waitForPostedBuffers() { @@ -2112,7 +2138,6 @@ protected: t.apply(true); } - sp mComposerClient; sp mBGSurfaceControl; sp mFGSurfaceControl; @@ -2122,10 +2147,10 @@ protected: }; TEST_F(LayerUpdateTest, RelativesAreNotDetached) { - sp sc; - sp relative = mComposerClient->createSurface(String8("relativeTestSurface"), 10, - 10, PIXEL_FORMAT_RGBA_8888, 0); + std::unique_ptr sc; + + sp relative = createLayer(String8("relativeTestSurface"), 10, 10, 0); fillSurfaceRGBA8(relative, 10, 10, 10); waitForPostedBuffers(); @@ -2188,7 +2213,7 @@ protected: EXPECT_INITIAL_STATE("After restoring initial state"); } - sp sc; + std::unique_ptr sc; }; class CropLatchingTest : public GeometryLatchingTest { @@ -2213,7 +2238,7 @@ protected: }; TEST_F(LayerUpdateTest, DeferredTransactionTest) { - sp sc; + std::unique_ptr sc; { SCOPED_TRACE("before anything"); ScreenCapture::captureScreen(&sc); @@ -2268,13 +2293,13 @@ TEST_F(LayerUpdateTest, DeferredTransactionTest) { } TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) { - sp sc; + std::unique_ptr sc; sp childNoBuffer = - mComposerClient->createSurface(String8("Bufferless child"), 10, 10, + mClient->createSurface(String8("Bufferless child"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); sp childBuffer = - mComposerClient->createSurface(String8("Buffered child"), 20, 20, + mClient->createSurface(String8("Buffered child"), 20, 20, PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get()); fillSurfaceRGBA8(childBuffer, 200, 200, 200); @@ -2296,7 +2321,7 @@ TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) { } TEST_F(LayerUpdateTest, MergingTransactions) { - sp sc; + std::unique_ptr sc; { SCOPED_TRACE("before move"); ScreenCapture::captureScreen(&sc); @@ -2323,13 +2348,13 @@ class ChildLayerTest : public LayerUpdateTest { protected: void SetUp() override { LayerUpdateTest::SetUp(); - mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + mChild = mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(mChild, 200, 200, 200); { SCOPED_TRACE("before anything"); - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectChildColor(64, 64); } } @@ -2339,7 +2364,7 @@ protected: } sp mChild; - sp mCapture; + std::unique_ptr mCapture; }; TEST_F(ChildLayerTest, ChildLayerPositioning) { @@ -2350,7 +2375,7 @@ TEST_F(ChildLayerTest, ChildLayerPositioning) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground must now be visible mCapture->expectFGColor(64, 64); // But 10 pixels in we should see the child surface @@ -2362,7 +2387,7 @@ TEST_F(ChildLayerTest, ChildLayerPositioning) { asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground should now be at 0, 0 mCapture->expectFGColor(0, 0); // But 10 pixels in we should see the child surface @@ -2381,7 +2406,7 @@ TEST_F(ChildLayerTest, ChildLayerCropping) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectChildColor(0, 0); mCapture->expectChildColor(4, 4); mCapture->expectBGColor(5, 5); @@ -2396,7 +2421,7 @@ TEST_F(ChildLayerTest, ChildLayerConstraints) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectFGColor(0, 0); // Last pixel in foreground should now be the child. mCapture->expectChildColor(63, 63); @@ -2411,7 +2436,7 @@ TEST_F(ChildLayerTest, ChildLayerScaling) { // Find the boundary between the parent and child { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectChildColor(9, 9); mCapture->expectFGColor(10, 10); } @@ -2421,7 +2446,7 @@ TEST_F(ChildLayerTest, ChildLayerScaling) { // The boundary should be twice as far from the origin now. // The pixels from the last test should all be child now { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectChildColor(9, 9); mCapture->expectChildColor(10, 10); mCapture->expectChildColor(19, 19); @@ -2442,7 +2467,7 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Unblended child color mCapture->checkPixel(0, 0, 0, 254, 0); } @@ -2450,7 +2475,7 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Child and BG blended. mCapture->checkPixel(0, 0, 127, 127, 0); } @@ -2458,7 +2483,7 @@ TEST_F(ChildLayerTest, ChildLayerAlpha) { asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Child and BG blended. mCapture->checkPixel(0, 0, 95, 64, 95); } @@ -2472,7 +2497,7 @@ TEST_F(ChildLayerTest, ReparentChildren) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground must now be visible mCapture->expectFGColor(64, 64); // But 10 pixels in we should see the child surface @@ -2486,7 +2511,7 @@ TEST_F(ChildLayerTest, ReparentChildren) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectFGColor(64, 64); // In reparenting we should have exposed the entire foreground surface. mCapture->expectFGColor(74, 74); @@ -2505,7 +2530,7 @@ TEST_F(ChildLayerTest, DetachChildrenSameClient) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground must now be visible mCapture->expectFGColor(64, 64); // But 10 pixels in we should see the child surface @@ -2514,6 +2539,7 @@ TEST_F(ChildLayerTest, DetachChildrenSameClient) { mCapture->expectFGColor(84, 84); } + asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); }); asTransaction([&](Transaction& t) { t.hide(mChild); }); @@ -2521,7 +2547,7 @@ TEST_F(ChildLayerTest, DetachChildrenSameClient) { // Since the child has the same client as the parent, it will not get // detached and will be hidden. { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectFGColor(64, 64); mCapture->expectFGColor(74, 74); mCapture->expectFGColor(84, 84); @@ -2547,7 +2573,7 @@ TEST_F(ChildLayerTest, DetachChildrenDifferentClient) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground must now be visible mCapture->expectFGColor(64, 64); // But 10 pixels in we should see the child surface @@ -2562,7 +2588,7 @@ TEST_F(ChildLayerTest, DetachChildrenDifferentClient) { // Nothing should have changed. { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectFGColor(64, 64); mCapture->expectChildColor(74, 74); mCapture->expectFGColor(84, 84); @@ -2577,7 +2603,7 @@ TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // We've positioned the child in the top left. mCapture->expectChildColor(0, 0); // But it's only 10x10. @@ -2591,7 +2617,7 @@ TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // We've positioned the child in the top left. mCapture->expectChildColor(0, 0); mCapture->expectChildColor(10, 10); @@ -2610,7 +2636,7 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // We've positioned the child in the top left. mCapture->expectChildColor(0, 0); // But it's only 10x10. @@ -2629,7 +2655,7 @@ TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) { { // The child should still be in the same place and not have any strange scaling as in // b/37673612. - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectChildColor(0, 0); mCapture->expectFGColor(10, 10); } @@ -2640,7 +2666,7 @@ TEST_F(ChildLayerTest, Bug36858924) { mChild.clear(); // Now recreate it as hidden - mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10, + mChild = mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden, mFGSurfaceControl.get()); @@ -2674,7 +2700,7 @@ TEST_F(ChildLayerTest, Reparent) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground must now be visible mCapture->expectFGColor(64, 64); // But 10 pixels in we should see the child surface @@ -2686,7 +2712,7 @@ TEST_F(ChildLayerTest, Reparent) { asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectFGColor(64, 64); // In reparenting we should have exposed the entire foreground surface. mCapture->expectFGColor(74, 74); @@ -2705,7 +2731,7 @@ TEST_F(ChildLayerTest, ReparentToNoParent) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground must now be visible mCapture->expectFGColor(64, 64); // But 10 pixels in we should see the child surface @@ -2715,7 +2741,7 @@ TEST_F(ChildLayerTest, ReparentToNoParent) { } asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Nothing should have changed. mCapture->expectFGColor(64, 64); mCapture->expectChildColor(74, 74); @@ -2724,8 +2750,7 @@ TEST_F(ChildLayerTest, ReparentToNoParent) { } TEST_F(ChildLayerTest, ReparentFromNoParent) { - sp newSurface = mComposerClient->createSurface(String8("New Surface"), 10, 10, - PIXEL_FORMAT_RGBA_8888, 0); + sp newSurface = createLayer(String8("New Surface"), 10, 10, 0); ASSERT_TRUE(newSurface != nullptr); ASSERT_TRUE(newSurface->isValid()); @@ -2739,7 +2764,7 @@ TEST_F(ChildLayerTest, ReparentFromNoParent) { }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Top left of foreground must now be visible mCapture->expectFGColor(64, 64); // At 10, 10 we should see the new surface @@ -2749,7 +2774,7 @@ TEST_F(ChildLayerTest, ReparentFromNoParent) { asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); }); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from // mFGSurface, putting it at 74, 74. mCapture->expectFGColor(64, 64); @@ -2760,12 +2785,12 @@ TEST_F(ChildLayerTest, ReparentFromNoParent) { TEST_F(ChildLayerTest, NestedChildren) { sp grandchild = - mComposerClient->createSurface(String8("Grandchild surface"), 10, 10, + mClient->createSurface(String8("Grandchild surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get()); fillSurfaceRGBA8(grandchild, 50, 50, 50); { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer // which begins at 64, 64 mCapture->checkPixel(64, 64, 50, 50, 50); @@ -2773,8 +2798,7 @@ TEST_F(ChildLayerTest, NestedChildren) { } TEST_F(ChildLayerTest, ChildLayerRelativeLayer) { - sp relative = mComposerClient->createSurface(String8("Relative surface"), 128, - 128, PIXEL_FORMAT_RGBA_8888, 0); + sp relative = createLayer(String8("Relative surface"), 128, 128, 0); fillSurfaceRGBA8(relative, 255, 255, 255); Transaction t; @@ -2786,7 +2810,7 @@ TEST_F(ChildLayerTest, ChildLayerRelativeLayer) { // We expect that the child should have been elevated above our // INT_MAX layer even though it's not a child of it. { - ScreenCapture::captureScreen(&mCapture); + mCapture = screenshot(); mCapture->expectChildColor(0, 0); mCapture->expectChildColor(9, 9); mCapture->checkPixel(10, 10, 255, 255, 255); @@ -2810,7 +2834,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithChild) { auto fgHandle = mFGSurfaceControl->getHandle(); sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(child, 200, 200, 200); @@ -2826,7 +2850,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) { auto fgHandle = mFGSurfaceControl->getHandle(); sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(child, 200, 200, 200); @@ -2840,7 +2864,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) { TEST_F(ScreenCaptureTest, CaptureTransparent) { sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(child, 200, 200, 200); @@ -2860,10 +2884,9 @@ TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) { auto fgHandle = mFGSurfaceControl->getHandle(); sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); - sp relative = mComposerClient->createSurface(String8("Relative surface"), 10, - 10, PIXEL_FORMAT_RGBA_8888, 0); + sp relative = createLayer(String8("Relative surface"), 10, 10, 0); fillSurfaceRGBA8(child, 200, 200, 200); fillSurfaceRGBA8(relative, 100, 100, 100); @@ -2884,10 +2907,10 @@ TEST_F(ScreenCaptureTest, CaptureRelativeInTree) { auto fgHandle = mFGSurfaceControl->getHandle(); sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); sp relative = - mComposerClient->createSurface(String8("Relative surface"), 10, 10, + mClient->createSurface(String8("Relative surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(child, 200, 200, 200); fillSurfaceRGBA8(relative, 100, 100, 100); @@ -2918,7 +2941,7 @@ public: LayerUpdateTest::SetUp(); mChild = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(mChild, 200, 200, 200); @@ -2976,12 +2999,12 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) { auto fgHandle = mFGSurfaceControl->getHandle(); sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(child, 200, 200, 200); sp grandchild = - mComposerClient->createSurface(String8("Grandchild surface"), 5, 5, + mClient->createSurface(String8("Grandchild surface"), 5, 5, PIXEL_FORMAT_RGBA_8888, 0, child.get()); fillSurfaceRGBA8(grandchild, 50, 50, 50); @@ -3000,7 +3023,7 @@ TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) { TEST_F(ScreenCaptureTest, CaptureChildOnly) { sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(child, 200, 200, 200); auto childHandle = child->getHandle(); @@ -3015,13 +3038,13 @@ TEST_F(ScreenCaptureTest, CaptureChildOnly) { TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) { sp child = - mComposerClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Child surface"), 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get()); fillSurfaceRGBA8(child, 200, 200, 200); auto childHandle = child->getHandle(); sp grandchild = - mComposerClient->createSurface(String8("Grandchild surface"), 5, 5, + mClient->createSurface(String8("Grandchild surface"), 5, 5, PIXEL_FORMAT_RGBA_8888, 0, child.get()); fillSurfaceRGBA8(grandchild, 50, 50, 50); @@ -3040,10 +3063,9 @@ TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) { } TEST_F(ScreenCaptureTest, CaptureCrop) { - sp redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60, - PIXEL_FORMAT_RGBA_8888, 0); + sp redLayer = createLayer(String8("Red surface"), 60, 60, 0); sp blueLayer = - mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get()); ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); @@ -3074,10 +3096,9 @@ TEST_F(ScreenCaptureTest, CaptureCrop) { } TEST_F(ScreenCaptureTest, CaptureSize) { - sp redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60, - PIXEL_FORMAT_RGBA_8888, 0); + sp redLayer = createLayer(String8("Red surface"), 60, 60, 0); sp blueLayer = - mComposerClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888, + mClient->createSurface(String8("Blue surface"), 30, 30, PIXEL_FORMAT_RGBA_8888, 0, redLayer.get()); ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); @@ -3110,13 +3131,12 @@ TEST_F(ScreenCaptureTest, CaptureSize) { } TEST_F(ScreenCaptureTest, CaptureInvalidLayer) { - sp redLayer = mComposerClient->createSurface(String8("Red surface"), 60, 60, - PIXEL_FORMAT_RGBA_8888, 0); + sp redLayer = createLayer(String8("Red surface"), 60, 60, 0); ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60)); auto redLayerHandle = redLayer->getHandle(); - mComposerClient->destroySurface(redLayerHandle); + mClient->destroySurface(redLayerHandle); SurfaceComposerClient::Transaction().apply(true); sp outBuffer; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 5aa6e27553..d52f0d87c3 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -185,8 +185,6 @@ void CompositionTest::captureScreenComposition() { LayerCase::setupForScreenCapture(this); const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); - constexpr int32_t minLayerZ = -1; - constexpr int32_t maxLayerZ = 1000; constexpr bool useIdentityTransform = true; constexpr bool forSystem = true; @@ -194,7 +192,7 @@ void CompositionTest::captureScreenComposition() { DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0); auto traverseLayers = [this](const LayerVector::Visitor& visitor) { - return mFlinger.traverseLayersInDisplay(mDisplay, minLayerZ, maxLayerZ, visitor); + return mFlinger.traverseLayersInDisplay(mDisplay, visitor); }; // TODO: Eliminate expensive/real allocation if possible. diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 341734cd63..f367275c76 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -121,10 +121,9 @@ public: useIdentityTransform, forSystem, outSyncFd); } - auto traverseLayersInDisplay(const sp& display, int32_t minLayerZ, - int32_t maxLayerZ, const LayerVector::Visitor& visitor) { - return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, minLayerZ, maxLayerZ, - visitor); + auto traverseLayersInDisplay(const sp& display, + const LayerVector::Visitor& visitor) { + return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, visitor); } /* ------------------------------------------------------------------------ -- cgit v1.2.3-59-g8ed1b From 0e003c90398640fe653c534bfec84335a31c0d63 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 17 Sep 2018 11:09:51 -0700 Subject: [SurfaceFlinger] Accept data space and pixel format to take screenshot. Previously we always take screenshot in SRGB data space. However, the current color mode of the display can be in a different color mode, and so can HWUI render in a different color space. Thus we want to remove the assumption that screenshot is captured in SRGB color space, and give the ability to the upper stack to specify the color space and pixel format it wants. BUG: 111436479 BUG: 116112787 Test: Build, flash, boot and take screenshot, observe there's no color shift. Test: Take screenshot, verified the color profile is correct of the png. Change-Id: I83a0682839f39a99bff6b471a33060dd570be9b0 --- libs/gui/ISurfaceComposer.cpp | 27 ++++++++--- libs/gui/SurfaceComposerClient.cpp | 27 ++++++----- libs/gui/include/gui/ISurfaceComposer.h | 53 +++++++++++++++++++++- libs/gui/include/gui/SurfaceComposerClient.h | 16 ++++--- libs/gui/tests/Surface_test.cpp | 29 +++++++----- services/surfaceflinger/DisplayDevice.h | 7 +-- services/surfaceflinger/RenderArea.h | 7 +++ services/surfaceflinger/SurfaceFlinger.cpp | 29 +++++++----- services/surfaceflinger/SurfaceFlinger.h | 12 +++-- services/surfaceflinger/tests/Credentials_test.cpp | 10 ++-- .../tests/unittests/CompositionTest.cpp | 5 +- 11 files changed, 161 insertions(+), 61 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f99bc5307c..cf9d4c5aba 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -103,11 +103,15 @@ public: } virtual status_t captureScreen(const sp& display, sp* outBuffer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { + const ui::Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(display); + data.writeInt32(static_cast(reqDataspace)); + data.writeInt32(static_cast(reqPixelFormat)); data.write(sourceCrop); data.writeUint32(reqWidth); data.writeUint32(reqHeight); @@ -126,15 +130,19 @@ public: *outBuffer = new GraphicBuffer(); reply.read(**outBuffer); + return result; } virtual status_t captureLayers(const sp& layerHandleBinder, - sp* outBuffer, const Rect& sourceCrop, + sp* outBuffer, const ui::Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, float frameScale, bool childrenOnly) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); data.writeStrongBinder(layerHandleBinder); + data.writeInt32(static_cast(reqDataspace)); + data.writeInt32(static_cast(reqPixelFormat)); data.write(sourceCrop); data.writeFloat(frameScale); data.writeBool(childrenOnly); @@ -148,6 +156,7 @@ public: ALOGE("captureLayers failed to readInt32: %d", result); return result; } + *outBuffer = new GraphicBuffer(); reply.read(**outBuffer); @@ -645,6 +654,8 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_SCREEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = data.readStrongBinder(); + ui::Dataspace reqDataspace = static_cast(data.readInt32()); + ui::PixelFormat reqPixelFormat = static_cast(data.readInt32()); sp outBuffer; Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); @@ -653,8 +664,8 @@ status_t BnSurfaceComposer::onTransact( bool useIdentityTransform = static_cast(data.readInt32()); int32_t rotation = data.readInt32(); - status_t res = captureScreen(display, &outBuffer, sourceCrop, reqWidth, reqHeight, - useIdentityTransform, + status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat, + sourceCrop, reqWidth, reqHeight, useIdentityTransform, static_cast(rotation)); reply->writeInt32(res); if (res == NO_ERROR) { @@ -665,14 +676,16 @@ status_t BnSurfaceComposer::onTransact( case CAPTURE_LAYERS: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp layerHandleBinder = data.readStrongBinder(); + ui::Dataspace reqDataspace = static_cast(data.readInt32()); + ui::PixelFormat reqPixelFormat = static_cast(data.readInt32()); sp outBuffer; Rect sourceCrop(Rect::EMPTY_RECT); data.read(sourceCrop); float frameScale = data.readFloat(); bool childrenOnly = data.readBool(); - status_t res = captureLayers(layerHandleBinder, &outBuffer, sourceCrop, frameScale, - childrenOnly); + status_t res = captureLayers(layerHandleBinder, &outBuffer, reqDataspace, + reqPixelFormat, sourceCrop, frameScale, childrenOnly); reply->writeInt32(res); if (res == NO_ERROR) { reply->write(*outBuffer); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 1ac96094cc..7498f365a0 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -887,13 +887,14 @@ status_t SurfaceComposerClient::getHdrCapabilities(const sp& display, // ---------------------------------------------------------------------------- -status_t ScreenshotClient::capture(const sp& display, Rect sourceCrop, uint32_t reqWidth, - uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation, - sp* outBuffer) { +status_t ScreenshotClient::capture(const sp& display, const ui::Dataspace reqDataSpace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, + uint32_t rotation, sp* outBuffer) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, - useIdentityTransform, + status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop, + reqWidth, reqHeight, useIdentityTransform, static_cast(rotation)); if (ret != NO_ERROR) { return ret; @@ -901,21 +902,25 @@ status_t ScreenshotClient::capture(const sp& display, Rect sourceCrop, return ret; } -status_t ScreenshotClient::captureLayers(const sp& layerHandle, Rect sourceCrop, +status_t ScreenshotClient::captureLayers(const sp& layerHandle, + const ui::Dataspace reqDataSpace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, float frameScale, sp* outBuffer) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, - false /* childrenOnly */); + status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat, + sourceCrop, frameScale, false /* childrenOnly */); return ret; } -status_t ScreenshotClient::captureChildLayers(const sp& layerHandle, Rect sourceCrop, +status_t ScreenshotClient::captureChildLayers(const sp& layerHandle, + const ui::Dataspace reqDataSpace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, float frameScale, sp* outBuffer) { sp s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale, - true /* childrenOnly */); + status_t ret = s->captureLayers(layerHandle, outBuffer, reqDataSpace, reqPixelFormat, + sourceCrop, frameScale, true /* childrenOnly */); return ret; } // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index a55cfe04d9..781e06275d 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -180,6 +180,36 @@ public: * The subregion can be optionally rotated. It will also be scaled to * match the size of the output buffer. * + * reqDataspace and reqPixelFormat specify the data space and pixel format + * of the buffer. The caller should pick the data space and pixel format + * that it can consume. + * + * At the moment, sourceCrop is ignored and is always set to the visible + * region (projected display viewport) of the screen. + * + * reqWidth and reqHeight specifies the size of the buffer. When either + * of them is 0, they are set to the size of the logical display viewport. + * + * When useIdentityTransform is true, layer transformations are disabled. + * + * rotation specifies the rotation of the source crop (and the pixels in + * it) around its center. + */ + virtual status_t captureScreen(const sp& display, sp* outBuffer, + const ui::Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, + Rotation rotation = eRotateNone) = 0; + /** + * Capture the specified screen. This requires READ_FRAME_BUFFER + * permission. This function will fail if there is a secure window on + * screen. + * + * This function can capture a subregion (the source crop) of the screen + * into an sRGB buffer with RGBA_8888 pixel format. + * The subregion can be optionally rotated. It will also be scaled to + * match the size of the output buffer. + * * At the moment, sourceCrop is ignored and is always set to the visible * region (projected display viewport) of the screen. * @@ -193,15 +223,34 @@ public: */ virtual status_t captureScreen(const sp& display, sp* outBuffer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform, Rotation rotation = eRotateNone) = 0; + bool useIdentityTransform, Rotation rotation = eRotateNone) { + return captureScreen(display, outBuffer, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, + sourceCrop, reqWidth, reqHeight, useIdentityTransform, rotation); + } /** * Capture a subtree of the layer hierarchy, potentially ignoring the root node. + * + * reqDataspace and reqPixelFormat specify the data space and pixel format + * of the buffer. The caller should pick the data space and pixel format + * that it can consume. */ virtual status_t captureLayers(const sp& layerHandleBinder, - sp* outBuffer, const Rect& sourceCrop, + sp* outBuffer, const ui::Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, float frameScale = 1.0, bool childrenOnly = false) = 0; + /** + * Capture a subtree of the layer hierarchy into an sRGB buffer with RGBA_8888 pixel format, + * potentially ignoring the root node. + */ + status_t captureLayers(const sp& layerHandleBinder, sp* outBuffer, + const Rect& sourceCrop, float frameScale = 1.0, + bool childrenOnly = false) { + return captureLayers(layerHandleBinder, outBuffer, ui::Dataspace::V0_SRGB, + ui::PixelFormat::RGBA_8888, sourceCrop, frameScale, childrenOnly); + } + /* Clears the frame statistics for animations. * * Requires the ACCESS_SURFACE_FLINGER permission. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 69a759fb4e..1b4eda720a 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -329,12 +329,16 @@ class ScreenshotClient { public: // if cropping isn't required, callers may pass in a default Rect, e.g.: // capture(display, producer, Rect(), reqWidth, ...); - static status_t capture(const sp& display, Rect sourceCrop, uint32_t reqWidth, - uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation, - sp* outBuffer); - static status_t captureLayers(const sp& layerHandle, Rect sourceCrop, float frameScale, - sp* outBuffer); - static status_t captureChildLayers(const sp& layerHandle, Rect sourceCrop, + static status_t capture(const sp& display, const ui::Dataspace reqDataSpace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, + uint32_t rotation, sp* outBuffer); + static status_t captureLayers(const sp& layerHandle, const ui::Dataspace reqDataSpace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + float frameScale, sp* outBuffer); + static status_t captureChildLayers(const sp& layerHandle, + const ui::Dataspace reqDataSpace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, float frameScale, sp* outBuffer); }; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index bc8089982c..500df055c2 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -134,8 +134,9 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { sp display(sf->getBuiltInDisplay( ISurfaceComposer::eDisplayIdMain)); sp outBuffer; - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), - 64, 64, false)); + ASSERT_EQ(NO_ERROR, + sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB, + ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU)); @@ -165,8 +166,9 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { &buf)); ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } - ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, Rect(), - 64, 64, false)); + ASSERT_EQ(NO_ERROR, + sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB, + ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false)); } TEST_F(SurfaceTest, ConcreteTypeIsSurface) { @@ -596,14 +598,19 @@ public: } status_t setActiveColorMode(const sp& /*display*/, ColorMode /*colorMode*/) override { return NO_ERROR; } - status_t captureScreen(const sp& /*display*/, - sp* /*outBuffer*/, - Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, - bool /*useIdentityTransform*/, - Rotation /*rotation*/) override { return NO_ERROR; } + status_t captureScreen(const sp& /*display*/, sp* /*outBuffer*/, + const ui::Dataspace /*reqDataspace*/, + const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/, + uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, + bool /*useIdentityTransform*/, Rotation /*rotation*/) override { + return NO_ERROR; + } virtual status_t captureLayers(const sp& /*parentHandle*/, - sp* /*outBuffer*/, const Rect& /*sourceCrop*/, - float /*frameScale*/, bool /*childrenOnly*/) override { + sp* /*outBuffer*/, + const ui::Dataspace /*reqDataspace*/, + const ui::PixelFormat /*reqPixelFormat*/, + const Rect& /*sourceCrop*/, float /*frameScale*/, + bool /*childrenOnly*/) override { return NO_ERROR; } status_t clearAnimationFrameStats() override { return NO_ERROR; } diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 38482c9dd5..918f7dec89 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -349,10 +349,11 @@ public: DisplayRenderArea(const sp device, ui::Transform::orientation_flags rotation = ui::Transform::ROT_0) : DisplayRenderArea(device, device->getBounds(), device->getWidth(), device->getHeight(), - rotation) {} + device->getCompositionDataSpace(), rotation) {} DisplayRenderArea(const sp device, Rect sourceCrop, uint32_t reqWidth, - uint32_t reqHeight, ui::Transform::orientation_flags rotation) - : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, + uint32_t reqHeight, ui::Dataspace reqDataSpace, + ui::Transform::orientation_flags rotation) + : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace, getDisplayRotation(rotation, device->getInstallOrientation())), mDevice(device), mSourceCrop(sourceCrop) {} diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h index 3c11e73199..9bad6dee04 100644 --- a/services/surfaceflinger/RenderArea.h +++ b/services/surfaceflinger/RenderArea.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -19,9 +20,11 @@ public: static float getCaptureFillValue(CaptureFill captureFill); RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill, + ui::Dataspace reqDataSpace, ui::Transform::orientation_flags rotation = ui::Transform::ROT_0) : mReqWidth(reqWidth), mReqHeight(reqHeight), + mReqDataSpace(reqDataSpace), mCaptureFill(captureFill), mRotationFlags(rotation) {} @@ -66,6 +69,9 @@ public: int getReqWidth() const { return mReqWidth; }; int getReqHeight() const { return mReqHeight; }; + // Returns the composition data space of the render area. + ui::Dataspace getReqDataSpace() const { return mReqDataSpace; } + // Returns the fill color of the physical render area. Regions not // covered by any rendered layer should be filled with this color. CaptureFill getCaptureFill() const { return mCaptureFill; }; @@ -73,6 +79,7 @@ public: private: const uint32_t mReqWidth; const uint32_t mReqHeight; + const ui::Dataspace mReqDataSpace; const CaptureFill mCaptureFill; const ui::Transform::orientation_flags mRotationFlags; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index f0723e897b..fe42480fb1 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5257,7 +5257,8 @@ private: }; status_t SurfaceFlinger::captureScreen(const sp& displayToken, - sp* outBuffer, Rect sourceCrop, + sp* outBuffer, const Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, ISurfaceComposer::Rotation rotation) { @@ -5286,23 +5287,27 @@ status_t SurfaceFlinger::captureScreen(const sp& displayToken, } } - DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, renderAreaRotation); + DisplayRenderArea renderArea(display, sourceCrop, reqWidth, reqHeight, reqDataspace, + renderAreaRotation); auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this, display, std::placeholders::_1); - return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform); + return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, + useIdentityTransform); } status_t SurfaceFlinger::captureLayers(const sp& layerHandleBinder, - sp* outBuffer, const Rect& sourceCrop, + sp* outBuffer, const Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, float frameScale, bool childrenOnly) { ATRACE_CALL(); class LayerRenderArea : public RenderArea { public: LayerRenderArea(SurfaceFlinger* flinger, const sp& layer, const Rect crop, - int32_t reqWidth, int32_t reqHeight, bool childrenOnly) - : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR), + int32_t reqWidth, int32_t reqHeight, Dataspace reqDataSpace, + bool childrenOnly) + : RenderArea(reqWidth, reqHeight, CaptureFill::CLEAR, reqDataSpace), mLayer(layer), mCrop(crop), mNeedsFiltering(false), @@ -5409,7 +5414,7 @@ status_t SurfaceFlinger::captureLayers(const sp& layerHandleBinder, reqHeight = 1; } - LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, childrenOnly); + LayerRenderArea renderArea(this, parent, crop, reqWidth, reqHeight, reqDataspace, childrenOnly); auto traverseLayers = [parent, childrenOnly](const LayerVector::Visitor& visitor) { parent->traverseChildrenInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) { @@ -5421,19 +5426,22 @@ status_t SurfaceFlinger::captureLayers(const sp& layerHandleBinder, visitor(layer); }); }; - return captureScreenCommon(renderArea, traverseLayers, outBuffer, false); + return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false); } status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, sp* outBuffer, + const ui::PixelFormat reqPixelFormat, bool useIdentityTransform) { ATRACE_CALL(); + // TODO(b/116112787) Make buffer usage a parameter. const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; *outBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(), - HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot"); + static_cast(reqPixelFormat), 1, usage, + "screenshot"); // This mutex protects syncFd and captureResult for communication of the return values from the // main thread back to this Binder thread @@ -5509,8 +5517,7 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, const auto sourceCrop = renderArea.getSourceCrop(); const auto rotation = renderArea.getRotationFlags(); - // assume ColorMode::SRGB / RenderIntent::COLORIMETRIC - engine.setOutputDataSpace(Dataspace::SRGB); + engine.setOutputDataSpace(renderArea.getReqDataSpace()); engine.setDisplayMaxLuminance(DisplayDevice::sDefaultMaxLumiance); // make sure to clear all GL error flags diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f535c4ed13..1425818271 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -433,10 +433,14 @@ private: virtual sp createDisplayEventConnection( ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp); virtual status_t captureScreen(const sp& displayToken, sp* outBuffer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation); + const ui::Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, + ISurfaceComposer::Rotation rotation); virtual status_t captureLayers(const sp& parentHandle, sp* outBuffer, - const Rect& sourceCrop, float frameScale, bool childrenOnly); + const ui::Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, + float frameScale, bool childrenOnly); virtual status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* stats); virtual status_t getDisplayConfigs(const sp& displayToken, Vector* configs); @@ -586,7 +590,7 @@ private: void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, bool useIdentityTransform); status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, - sp* outBuffer, + sp* outBuffer, const ui::PixelFormat reqPixelFormat, bool useIdentityTransform); status_t captureScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 9e762f0eb1..a73ec6c7ef 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -267,8 +267,9 @@ TEST_F(CredentialsTest, CaptureTest) { sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); std::function condition = [=]() { sp outBuffer; - return ScreenshotClient::capture(display, Rect(), 0 /*reqWidth*/, 0 /*reqHeight*/, false, - ROTATION, &outBuffer); + return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB, + ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/, + 0 /*reqHeight*/, false, ROTATION, &outBuffer); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } @@ -278,8 +279,9 @@ TEST_F(CredentialsTest, CaptureLayersTest) { sp outBuffer; std::function condition = [=]() { sp outBuffer; - return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), Rect(), FRAME_SCALE, - &outBuffer); + return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(), + ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, + Rect(), FRAME_SCALE, &outBuffer); }; ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 4e403b79ca..f4306794f3 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -189,7 +189,8 @@ void CompositionTest::captureScreenComposition() { constexpr bool forSystem = true; DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH, - DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0); + DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB, + ui::Transform::ROT_0); auto traverseLayers = [this](const LayerVector::Visitor& visitor) { return mFlinger.traverseLayersInDisplay(mDisplay, visitor); @@ -287,7 +288,7 @@ struct BaseDisplayVariant { EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd()))); EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true)); - EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1); + EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(_)).Times(1); EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE)) .Times(1); // This expectation retires on saturation as setViewportAndProjection is -- cgit v1.2.3-59-g8ed1b From 2a6ab2aa52b9657b6c7b4401b3ec225c3a65b5c3 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Fri, 26 Oct 2018 14:25:30 -0700 Subject: SurfaceFlinger: fix color transfer test Add support for color management in LayerTransactionTest.SetColorTransformBasic. If color management is enabled, some considerations are needed for the expected color output. Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test Change-Id: I7be7d561e7683fd57db0519932c4c308a6350c0d --- libs/gui/ISurfaceComposer.cpp | 21 ++++++ libs/gui/include/gui/ISurfaceComposer.h | 3 + libs/gui/tests/Surface_test.cpp | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 5 ++ services/surfaceflinger/SurfaceFlinger.h | 1 + services/surfaceflinger/tests/Transaction_test.cpp | 74 ++++++++++++++++++++-- 6 files changed, 101 insertions(+), 5 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index cf9d4c5aba..cc0a307c65 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -583,6 +583,21 @@ public: } return error; } + + virtual bool isColorManagementUsed() const { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::IS_COLOR_MANAGEMET_USED, data, &reply); + int32_t result = 0; + status_t err = reply.readInt32(&result); + if (err != NO_ERROR) { + ALOGE("ISurfaceComposer::isColorManagementUsed: error " + "retrieving result: %s (%d)", + strerror(-err), -err); + return false; + } + return result != 0; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -920,6 +935,12 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } + case IS_COLOR_MANAGEMET_USED: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + int32_t result = isColorManagementUsed() ? 1 : 0; + reply->writeInt32(result); + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 781e06275d..35cb3be7df 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -282,6 +282,8 @@ public: virtual status_t getCompositionPreference(ui::Dataspace* dataSpace, ui::PixelFormat* pixelFormat) const = 0; + + virtual bool isColorManagementUsed() const = 0; }; // ---------------------------------------------------------------------------- @@ -320,6 +322,7 @@ public: GET_LAYER_DEBUG_INFO, CREATE_SCOPED_CONNECTION, GET_COMPOSITION_PREFERENCE, + IS_COLOR_MANAGEMET_USED, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 500df055c2..25f762bbe3 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -633,6 +633,8 @@ public: return NO_ERROR; } + virtual bool isColorManagementUsed() const { return false; } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index ab07bc6815..fc8ca54797 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -513,6 +513,10 @@ sp SurfaceFlinger::getBuiltInDisplay(int32_t id) { return mDisplayTokens[id]; } +bool SurfaceFlinger::isColorManagementUsed() const { + return useColorManagement; +} + void SurfaceFlinger::bootFinished() { if (mStartPropertySetThread->join() != NO_ERROR) { @@ -4744,6 +4748,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_TRANSACTION_STATE: // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h case CREATE_SCOPED_CONNECTION: + case IS_COLOR_MANAGEMET_USED: case GET_COMPOSITION_PREFERENCE: { return OK; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 9e47b3fd9f..73c9d952d9 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -462,6 +462,7 @@ private: virtual status_t getLayerDebugInfo(std::vector* outLayers) const; status_t getCompositionPreference(ui::Dataspace* outDataSpace, ui::PixelFormat* outPixelFormat) const override; + virtual bool isColorManagementUsed() const; /* ------------------------------------------------------------------------ * DeathRecipient interface diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 3166a8c752..c814142f49 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -314,6 +315,10 @@ protected: ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient"; ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); + + sp sf(ComposerService::getComposerService()); + sp binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); + mColorManagementUsed = sf->isColorManagementUsed(); } virtual void TearDown() { @@ -470,6 +475,8 @@ protected: void setMatrixWithResizeHelper(uint32_t layerType); sp mBlackBgSurface; + bool mColorManagementUsed; + private: void SetUpDisplay() { mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); @@ -2064,6 +2071,47 @@ TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) { Transaction().setSidebandStream(layer, nullptr).apply(); } +class ColorTransformHelper { +public: + static void DegammaColorSingle(half& s) { + if (s <= 0.03928f) + s = s / 12.92f; + else + s = pow((s + 0.055f) / 1.055f, 2.4f); + } + + static void DegammaColor(half3& color) { + DegammaColorSingle(color.r); + DegammaColorSingle(color.g); + DegammaColorSingle(color.b); + } + + static void GammaColorSingle(half& s) { + if (s <= 0.0031308f) { + s = s * 12.92f; + } else { + s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f; + } + } + + static void GammaColor(half3& color) { + GammaColorSingle(color.r); + GammaColorSingle(color.g); + GammaColorSingle(color.b); + } + + static void applyMatrix(half3& color, const mat3& mat) { + half3 ret = half3(0); + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + ret[i] = ret[i] + color[j] * mat[j][i]; + } + } + color = ret; + } +}; + TEST_F(LayerTransactionTest, SetColorTransformBasic) { sp colorLayer; ASSERT_NO_FATAL_FAILURE( @@ -2076,19 +2124,35 @@ TEST_F(LayerTransactionTest, SetColorTransformBasic) { } const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f); - const Color expected = {90, 90, 90, 255}; - // this is handwavy, but the precison loss scaled by 255 (8-bit per - // channel) should be less than one - const uint8_t tolerance = 1; + half3 expected = color; mat3 matrix; matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11; matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11; matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11; + + // degamma before applying the matrix + if (mColorManagementUsed) { + ColorTransformHelper::DegammaColor(expected); + } + + ColorTransformHelper::applyMatrix(expected, matrix); + + if (mColorManagementUsed) { + ColorTransformHelper::GammaColor(expected); + } + + const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255), + uint8_t(expected.b * 255), 255}; + + // this is handwavy, but the precison loss scaled by 255 (8-bit per + // channel) should be less than one + const uint8_t tolerance = 1; + Transaction().setColor(colorLayer, color) .setColorTransform(colorLayer, matrix, vec3()).apply(); { SCOPED_TRACE("new color"); - screenshot()->expectColor(Rect(0, 0, 32, 32), expected, tolerance); + screenshot()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance); } } -- cgit v1.2.3-59-g8ed1b From c678097979379cdf59a91697a1fcfa020cda70b6 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Sun, 28 Oct 2018 15:24:08 -0700 Subject: [SurfaceFlinger] Expose WCG composition preference through ISurfaceComposer API. Previously we introduced an API to return default composition preference. However, wide color gamut composition preference is very likely to be different than the default composition preference. This patch also exposes this information back to upper stack, notable HWUI, to make sure upper stack has the flexibility to render into desired format for wide color gamut surfaces. BUG: 111436479 Test: Build, flash and boot, run some display validation. Change-Id: Ic05747591e62ca5f3c396704390555b7f545c31c --- libs/gui/ISurfaceComposer.cpp | 28 +++++++++++++++-------- libs/gui/SurfaceComposerClient.cpp | 9 +++++--- libs/gui/include/gui/ISurfaceComposer.h | 15 ++++++++++--- libs/gui/include/gui/SurfaceComposerClient.h | 12 +++++++--- libs/gui/tests/Surface_test.cpp | 6 +++-- services/surfaceflinger/SurfaceFlinger.cpp | 33 ++++++++++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 15 +++++++++---- 7 files changed, 82 insertions(+), 36 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index cc0a307c65..e66c0e5dd6 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -565,8 +565,10 @@ public: return reply.readParcelableVector(outLayers); } - virtual status_t getCompositionPreference(ui::Dataspace* dataSpace, - ui::PixelFormat* pixelFormat) const { + virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace, + ui::PixelFormat* defaultPixelFormat, + ui::Dataspace* wideColorGamutDataspace, + ui::PixelFormat* wideColorGamutPixelFormat) const { Parcel data, reply; status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); if (error != NO_ERROR) { @@ -578,8 +580,10 @@ public: } error = static_cast(reply.readInt32()); if (error == NO_ERROR) { - *dataSpace = static_cast(reply.readInt32()); - *pixelFormat = static_cast(reply.readInt32()); + *defaultDataspace = static_cast(reply.readInt32()); + *defaultPixelFormat = static_cast(reply.readInt32()); + *wideColorGamutDataspace = static_cast(reply.readInt32()); + *wideColorGamutPixelFormat = static_cast(reply.readInt32()); } return error; } @@ -925,13 +929,19 @@ status_t BnSurfaceComposer::onTransact( } case GET_COMPOSITION_PREFERENCE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::Dataspace dataSpace; - ui::PixelFormat pixelFormat; - status_t error = getCompositionPreference(&dataSpace, &pixelFormat); + ui::Dataspace defaultDataspace; + ui::PixelFormat defaultPixelFormat; + ui::Dataspace wideColorGamutDataspace; + ui::PixelFormat wideColorGamutPixelFormat; + status_t error = + getCompositionPreference(&defaultDataspace, &defaultPixelFormat, + &wideColorGamutDataspace, &wideColorGamutPixelFormat); reply->writeInt32(error); if (error == NO_ERROR) { - reply->writeInt32(static_cast(dataSpace)); - reply->writeInt32(static_cast(pixelFormat)); + reply->writeInt32(static_cast(defaultDataspace)); + reply->writeInt32(static_cast(defaultPixelFormat)); + reply->writeInt32(static_cast(wideColorGamutDataspace)); + reply->writeInt32(static_cast(wideColorGamutDataspace)); } return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 7498f365a0..e5a2454db3 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -866,9 +866,12 @@ void SurfaceComposerClient::setDisplayPowerMode(const sp& token, ComposerService::getComposerService()->setPowerMode(token, mode); } -status_t SurfaceComposerClient::getCompositionPreference(ui::Dataspace* dataSpace, - ui::PixelFormat* pixelFormat) { - return ComposerService::getComposerService()->getCompositionPreference(dataSpace, pixelFormat); +status_t SurfaceComposerClient::getCompositionPreference( + ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat, + ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) { + return ComposerService::getComposerService() + ->getCompositionPreference(defaultDataspace, defaultPixelFormat, + wideColorGamutDataspace, wideColorGamutPixelFormat); } status_t SurfaceComposerClient::clearAnimationFrameStats() { diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 35cb3be7df..9316ae69bc 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -280,10 +280,19 @@ public: */ virtual status_t getLayerDebugInfo(std::vector* outLayers) const = 0; - virtual status_t getCompositionPreference(ui::Dataspace* dataSpace, - ui::PixelFormat* pixelFormat) const = 0; - virtual bool isColorManagementUsed() const = 0; + + /* Gets the composition preference of the default data space and default pixel format, + * as well as the wide color gamut data space and wide color gamut pixel format. + * If the wide color gamut data space is V0_SRGB, then it implies that the platform + * has no wide color gamut support. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace, + ui::PixelFormat* defaultPixelFormat, + ui::Dataspace* wideColorGamutDataspace, + ui::PixelFormat* wideColorGamutPixelFormat) const = 0; }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 1b4eda720a..8ccee05ba4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -101,9 +101,15 @@ public: /* Triggers screen on/off or low power mode and waits for it to complete */ static void setDisplayPowerMode(const sp& display, int mode); - // - static status_t getCompositionPreference(ui::Dataspace* dataSpace, - ui::PixelFormat* pixelFormat); + /* Returns the composition preference of the default data space and default pixel format, + * as well as the wide color gamut data space and wide color gamut pixel format. + * If the wide color gamut data space is V0_SRGB, then it implies that the platform + * has no wide color gamut support. + */ + static status_t getCompositionPreference(ui::Dataspace* defaultDataspace, + ui::PixelFormat* defaultPixelFormat, + ui::Dataspace* wideColorGamutDataspace, + ui::PixelFormat* wideColorGamutPixelFormat); // ------------------------------------------------------------------------ // surface creation / destruction diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 25f762bbe3..a3e9249ac2 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -628,8 +628,10 @@ public: status_t getLayerDebugInfo(std::vector* /*layers*/) const override { return NO_ERROR; } - status_t getCompositionPreference(ui::Dataspace* /*outDataSpace*/, - ui::PixelFormat* /*outPixelFormat*/) const override { + status_t getCompositionPreference( + ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/, + ui::Dataspace* /*outWideColorGamutDataspace*/, + ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override { return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fc8ca54797..5c31ada5ef 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -196,8 +196,10 @@ bool SurfaceFlinger::hasWideColorDisplay; int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault; bool SurfaceFlinger::useColorManagement; bool SurfaceFlinger::useContextPriority; -Dataspace SurfaceFlinger::compositionDataSpace = Dataspace::V0_SRGB; -ui::PixelFormat SurfaceFlinger::compositionPixelFormat = ui::PixelFormat::RGBA_8888; +Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB; +ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888; +Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB; +ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; std::string getHwcServiceName() { char value[PROPERTY_VALUE_MAX] = {}; @@ -303,10 +305,13 @@ SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory) auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService(); if (surfaceFlingerConfigsServiceV1_2) { surfaceFlingerConfigsServiceV1_2->getCompositionPreference( - [&](Dataspace tmpDataSpace, ui::PixelFormat tmpPixelFormat) { - compositionDataSpace = tmpDataSpace; - compositionPixelFormat = tmpPixelFormat; - }); + [&](auto tmpDefaultDataspace, auto tmpDefaultPixelFormat, + auto tmpWideColorGamutDataspace, auto tmpWideColorGamutPixelFormat) { + defaultCompositionDataspace = tmpDefaultDataspace; + defaultCompositionPixelFormat = tmpDefaultPixelFormat; + wideColorGamutCompositionDataspace = tmpWideColorGamutDataspace; + wideColorGamutCompositionPixelFormat = tmpWideColorGamutPixelFormat; + }); } useContextPriority = getBool(compositionPixelFormat), - renderEngineFeature); + renderengine::RenderEngine::create(static_cast(defaultCompositionPixelFormat), + renderEngineFeature); LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine"); LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay, @@ -1157,10 +1162,14 @@ status_t SurfaceFlinger::getLayerDebugInfo(std::vector* outLayer return NO_ERROR; } -status_t SurfaceFlinger::getCompositionPreference(Dataspace* outDataSpace, - ui::PixelFormat* outPixelFormat) const { - *outDataSpace = compositionDataSpace; - *outPixelFormat = compositionPixelFormat; +status_t SurfaceFlinger::getCompositionPreference( + Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, + Dataspace* outWideColorGamutDataspace, + ui::PixelFormat* outWideColorGamutPixelFormat) const { + *outDataspace = defaultCompositionDataspace; + *outPixelFormat = defaultCompositionPixelFormat; + *outWideColorGamutDataspace = wideColorGamutCompositionDataspace; + *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat; return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 73c9d952d9..d60765cc1a 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -294,8 +294,14 @@ public: // The data space and pixel format that SurfaceFlinger expects hardware composer // to composite efficiently. Meaning under most scenarios, hardware composer // will accept layers with the data space and pixel format. - static ui::Dataspace compositionDataSpace; - static ui::PixelFormat compositionPixelFormat; + static ui::Dataspace defaultCompositionDataspace; + static ui::PixelFormat defaultCompositionPixelFormat; + + // The data space and pixel format that SurfaceFlinger expects hardware composer + // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios, + // hardware composer will accept layers with the data space and pixel format. + static ui::Dataspace wideColorGamutCompositionDataspace; + static ui::PixelFormat wideColorGamutCompositionPixelFormat; static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; @@ -460,9 +466,10 @@ private: virtual status_t enableVSyncInjections(bool enable); virtual status_t injectVSync(nsecs_t when); virtual status_t getLayerDebugInfo(std::vector* outLayers) const; - status_t getCompositionPreference(ui::Dataspace* outDataSpace, - ui::PixelFormat* outPixelFormat) const override; virtual bool isColorManagementUsed() const; + status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, + ui::Dataspace* outWideColorGamutDataspace, + ui::PixelFormat* outWideColorGamutPixelFormat) const override; /* ------------------------------------------------------------------------ * DeathRecipient interface -- cgit v1.2.3-59-g8ed1b From 37965d4d225e333b70110c5715998eebed5eedd2 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 1 Nov 2018 13:43:32 -0700 Subject: ISurfaceComposer: rename isColorManagementUsed() Rename isColorManagementUsed() to getColorManagement() to follow the convention in ISurfaceComposer. Test: adb shell /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter=LayerTransactionTest.SetColorTransformBasic Change-Id: I63f75a98dbd230375f215a109a725672353eceef --- libs/gui/ISurfaceComposer.cpp | 28 +++++++++++----------- libs/gui/include/gui/ISurfaceComposer.h | 4 ++-- libs/gui/tests/Surface_test.cpp | 2 +- services/surfaceflinger/SurfaceFlinger.cpp | 10 +++++--- services/surfaceflinger/SurfaceFlinger.h | 2 +- services/surfaceflinger/tests/Transaction_test.cpp | 2 +- 6 files changed, 26 insertions(+), 22 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index e66c0e5dd6..accf72c390 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -588,19 +588,16 @@ public: return error; } - virtual bool isColorManagementUsed() const { + virtual status_t getColorManagement(bool* outGetColorManagement) const { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::IS_COLOR_MANAGEMET_USED, data, &reply); - int32_t result = 0; - status_t err = reply.readInt32(&result); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::isColorManagementUsed: error " - "retrieving result: %s (%d)", - strerror(-err), -err); - return false; + remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply); + bool result; + status_t err = reply.readBool(&result); + if (err == NO_ERROR) { + *outGetColorManagement = result; } - return result != 0; + return err; } }; @@ -945,11 +942,14 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } - case IS_COLOR_MANAGEMET_USED: { + case GET_COLOR_MANAGEMENT: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t result = isColorManagementUsed() ? 1 : 0; - reply->writeInt32(result); - return NO_ERROR; + bool result; + status_t error = getColorManagement(&result); + if (error == NO_ERROR) { + reply->writeBool(result); + } + return result; } default: { return BBinder::onTransact(code, data, reply, flags); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 9316ae69bc..761f31a04b 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -280,7 +280,7 @@ public: */ virtual status_t getLayerDebugInfo(std::vector* outLayers) const = 0; - virtual bool isColorManagementUsed() const = 0; + virtual status_t getColorManagement(bool* outGetColorManagement) const = 0; /* Gets the composition preference of the default data space and default pixel format, * as well as the wide color gamut data space and wide color gamut pixel format. @@ -331,7 +331,7 @@ public: GET_LAYER_DEBUG_INFO, CREATE_SCOPED_CONNECTION, GET_COMPOSITION_PREFERENCE, - IS_COLOR_MANAGEMET_USED, + GET_COLOR_MANAGEMENT, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index a3e9249ac2..d0600daa0d 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -635,7 +635,7 @@ public: return NO_ERROR; } - virtual bool isColorManagementUsed() const { return false; } + virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5c31ada5ef..968fcd6acb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -518,8 +518,12 @@ sp SurfaceFlinger::getBuiltInDisplay(int32_t id) { return mDisplayTokens[id]; } -bool SurfaceFlinger::isColorManagementUsed() const { - return useColorManagement; +status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const { + if (!outGetColorManagement) { + return BAD_VALUE; + } + *outGetColorManagement = useColorManagement; + return NO_ERROR; } void SurfaceFlinger::bootFinished() @@ -4757,7 +4761,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_TRANSACTION_STATE: // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h case CREATE_SCOPED_CONNECTION: - case IS_COLOR_MANAGEMET_USED: + case GET_COLOR_MANAGEMENT: case GET_COMPOSITION_PREFERENCE: { return OK; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index d60765cc1a..f670f0b5d3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -466,7 +466,7 @@ private: virtual status_t enableVSyncInjections(bool enable); virtual status_t injectVSync(nsecs_t when); virtual status_t getLayerDebugInfo(std::vector* outLayers) const; - virtual bool isColorManagementUsed() const; + virtual status_t getColorManagement(bool* outGetColorManagement) const; status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, ui::Dataspace* outWideColorGamutDataspace, ui::PixelFormat* outWideColorGamutPixelFormat) const override; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index c814142f49..edb82d0005 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -318,7 +318,7 @@ protected: sp sf(ComposerService::getComposerService()); sp binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); - mColorManagementUsed = sf->isColorManagementUsed(); + ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed)); } virtual void TearDown() { -- cgit v1.2.3-59-g8ed1b From c837b5ecc406f6bf6e5424d48435b56decbd903e Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 12 Oct 2018 10:04:44 -0700 Subject: blast: Send transaction listener from SCC to SF Send the TransactionCompletedListeners to SurfaceFlinger via transactions. The listener will be used to send callbacks after a transaction has completed. Test: Transaction_test Bug: 80477568 Change-Id: I51d3877f2803a192f95db4dd211f48aca9651c30 --- libs/gui/ISurfaceComposer.cpp | 2 +- libs/gui/LayerState.cpp | 19 +++ libs/gui/SurfaceComposerClient.cpp | 131 ++++++++++++++++++++- .../include/gui/ITransactionCompletedListener.h | 18 +++ libs/gui/include/gui/LayerState.h | 4 + libs/gui/include/gui/SurfaceComposerClient.h | 41 ++++++- 6 files changed, 210 insertions(+), 5 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index accf72c390..69e5379047 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -634,10 +634,10 @@ status_t BnSurfaceComposer::onTransact( if (count > data.dataSize()) { return BAD_VALUE; } - ComposerState s; Vector state; state.setCapacity(count); for (size_t i = 0; i < count; i++) { + ComposerState s; if (s.read(data) == BAD_VALUE) { return BAD_VALUE; } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 2b0a46181b..7b71b39ce0 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -80,6 +80,13 @@ status_t layer_state_t::write(Parcel& output) const memcpy(output.writeInplace(16 * sizeof(float)), colorTransform.asArray(), 16 * sizeof(float)); + if (output.writeVectorSize(listenerCallbacks) == NO_ERROR) { + for (const auto& [listener, callbackIds] : listenerCallbacks) { + output.writeStrongBinder(IInterface::asBinder(listener)); + output.writeInt64Vector(callbackIds); + } + } + return NO_ERROR; } @@ -135,6 +142,14 @@ status_t layer_state_t::read(const Parcel& input) colorTransform = mat4(static_cast(input.readInplace(16 * sizeof(float)))); + int32_t listenersSize = input.readInt32(); + for (int32_t i = 0; i < listenersSize; i++) { + auto listener = interface_cast(input.readStrongBinder()); + std::vector callbackIds; + input.readInt64Vector(&callbackIds); + listenerCallbacks.emplace_back(listener, callbackIds); + } + return NO_ERROR; } @@ -323,6 +338,10 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eColorTransformChanged; colorTransform = other.colorTransform; } + if (other.what & eListenerCallbacksChanged) { + what |= eListenerCallbacksChanged; + listenerCallbacks = other.listenerCallbacks; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 84df7a9a3d..88c574286b 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -104,13 +104,23 @@ void ComposerService::composerServiceDied() // to be able to return a sp<> to its instance to pass to SurfaceFlinger. // ANDROID_SINGLETON_STATIC_INSTANCE only allows a reference to an instance. +// 0 is an invalid callback id +TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {} + +CallbackId TransactionCompletedListener::getNextIdLocked() { + return mCallbackIdCounter++; +} + sp TransactionCompletedListener::getInstance() { static sp sInstance = new TransactionCompletedListener; return sInstance; } -void TransactionCompletedListener::startListening() { - std::lock_guard lock(mMutex); +sp TransactionCompletedListener::getIInstance() { + return static_cast>(getInstance()); +} + +void TransactionCompletedListener::startListeningLocked() { if (mListening) { return; } @@ -118,6 +128,16 @@ void TransactionCompletedListener::startListening() { mListening = true; } +CallbackId TransactionCompletedListener::addCallback( + const TransactionCompletedCallbackWithContext& callback) { + std::lock_guard lock(mMutex); + startListeningLocked(); + + CallbackId callbackId = getNextIdLocked(); + mCallbacks.emplace(callbackId, callback); + return callbackId; +} + void TransactionCompletedListener::onTransactionCompleted() { return; } @@ -153,6 +173,17 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr } other.mDisplayStates.clear(); + for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { + auto& [callbackIds, surfaceControls] = callbackInfo; + mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator( + callbackIds.begin()), + std::make_move_iterator(callbackIds.end())); + mListenerCallbacks[listener] + .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()), + std::make_move_iterator(surfaceControls.end())); + } + other.mListenerCallbacks.clear(); + return *this; } @@ -163,6 +194,26 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { sp sf(ComposerService::getComposerService()); + // For every listener with registered callbacks + for (const auto& [listener, callbackInfo] : mListenerCallbacks) { + auto& [callbackIds, surfaceControls] = callbackInfo; + if (callbackIds.empty()) { + continue; + } + + // If the listener has any SurfaceControls set on this Transaction update the surface state + for (const auto& surfaceControl : surfaceControls) { + layer_state_t* s = getLayerState(surfaceControl); + if (!s) { + ALOGE("failed to get layer state"); + continue; + } + s->what |= layer_state_t::eListenerCallbacksChanged; + s->listenerCallbacks.emplace_back(listener, std::move(callbackIds)); + } + } + mListenerCallbacks.clear(); + Vector composerStates; Vector displayStates; uint32_t flags = 0; @@ -232,6 +283,11 @@ layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& sc) { + mListenerCallbacks[TransactionCompletedListener::getIInstance()].surfaceControls.insert(sc); +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition( const sp& sc, float x, float y) { layer_state_t* s = getLayerState(sc); @@ -242,6 +298,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosit s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; + + registerSurfaceControlForCallback(sc); return *this; } @@ -266,6 +324,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSize( s->w = w; s->h = h; + registerSurfaceControlForCallback(sc); return *this; } @@ -278,6 +337,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer } s->what |= layer_state_t::eLayerChanged; s->z = z; + + registerSurfaceControlForCallback(sc); return *this; } @@ -290,6 +351,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelat s->what |= layer_state_t::eRelativeLayerChanged; s->relativeLayerHandle = relativeTo; s->z = z; + + registerSurfaceControlForCallback(sc); return *this; } @@ -309,6 +372,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; + + registerSurfaceControlForCallback(sc); return *this; } @@ -322,6 +387,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrans } s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; + + registerSurfaceControlForCallback(sc); return *this; } @@ -334,6 +401,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha } s->what |= layer_state_t::eAlphaChanged; s->alpha = alpha; + + registerSurfaceControlForCallback(sc); return *this; } @@ -346,6 +415,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer } s->what |= layer_state_t::eLayerStackChanged; s->layerStack = layerStack; + + registerSurfaceControlForCallback(sc); return *this; } @@ -364,6 +435,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatri matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; + + registerSurfaceControlForCallback(sc); return *this; } @@ -376,6 +449,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop_ } s->what |= layer_state_t::eCropChanged_legacy; s->crop_legacy = crop; + + registerSurfaceControlForCallback(sc); return *this; } @@ -391,6 +466,8 @@ SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const spwhat |= layer_state_t::eDeferTransaction_legacy; s->barrierHandle_legacy = handle; s->frameNumber_legacy = frameNumber; + + registerSurfaceControlForCallback(sc); return *this; } @@ -406,6 +483,8 @@ SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(const spwhat |= layer_state_t::eDeferTransaction_legacy; s->barrierGbp_legacy = barrierSurface->getIGraphicBufferProducer(); s->frameNumber_legacy = frameNumber; + + registerSurfaceControlForCallback(sc); return *this; } @@ -419,6 +498,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent } s->what |= layer_state_t::eReparentChildren; s->reparentHandle = newParentHandle; + + registerSurfaceControlForCallback(sc); return *this; } @@ -432,6 +513,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent } s->what |= layer_state_t::eReparent; s->parentHandleForChild = newParentHandle; + + registerSurfaceControlForCallback(sc); return *this; } @@ -445,6 +528,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor } s->what |= layer_state_t::eColorChanged; s->color = color; + + registerSurfaceControlForCallback(sc); return *this; } @@ -457,6 +542,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrans } s->what |= layer_state_t::eTransformChanged; s->transform = transform; + + registerSurfaceControlForCallback(sc); return *this; } @@ -470,6 +557,8 @@ SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const spwhat |= layer_state_t::eTransformToDisplayInverseChanged; s->transformToDisplayInverse = transformToDisplayInverse; + + registerSurfaceControlForCallback(sc); return *this; } @@ -482,6 +571,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( } s->what |= layer_state_t::eCropChanged; s->crop = crop; + + registerSurfaceControlForCallback(sc); return *this; } @@ -494,6 +585,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe } s->what |= layer_state_t::eBufferChanged; s->buffer = buffer; + + registerSurfaceControlForCallback(sc); return *this; } @@ -506,6 +599,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcqui } s->what |= layer_state_t::eAcquireFenceChanged; s->acquireFence = fence; + + registerSurfaceControlForCallback(sc); return *this; } @@ -518,6 +613,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDatas } s->what |= layer_state_t::eDataspaceChanged; s->dataspace = dataspace; + + registerSurfaceControlForCallback(sc); return *this; } @@ -530,6 +627,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMe } s->what |= layer_state_t::eHdrMetadataChanged; s->hdrMetadata = hdrMetadata; + + registerSurfaceControlForCallback(sc); return *this; } @@ -542,6 +641,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSurfa } s->what |= layer_state_t::eSurfaceDamageRegionChanged; s->surfaceDamageRegion = surfaceDamageRegion; + + registerSurfaceControlForCallback(sc); return *this; } @@ -554,6 +655,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApi( } s->what |= layer_state_t::eApiChanged; s->api = api; + + registerSurfaceControlForCallback(sc); return *this; } @@ -566,6 +669,22 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSideb } s->what |= layer_state_t::eSidebandStreamChanged; s->sidebandStream = sidebandStream; + + registerSurfaceControlForCallback(sc); + return *this; +} + +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::addTransactionCompletedCallback( + TransactionCompletedCallback callback, void* callbackContext) { + auto listener = TransactionCompletedListener::getInstance(); + + auto callbackWithContext = std::bind(callback, callbackContext); + + CallbackId callbackId = listener->addCallback(callbackWithContext); + + mListenerCallbacks[TransactionCompletedListener::getIInstance()].callbackIds.emplace( + callbackId); return *this; } @@ -576,6 +695,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachCh mStatus = BAD_INDEX; } s->what |= layer_state_t::eDetachChildren; + + registerSurfaceControlForCallback(sc); return *this; } @@ -603,6 +724,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverr s->what |= layer_state_t::eOverrideScalingModeChanged; s->overrideScalingMode = overrideScalingMode; + + registerSurfaceControlForCallback(sc); return *this; } @@ -614,6 +737,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeome return *this; } s->what |= layer_state_t::eGeometryAppliesWithResize; + + registerSurfaceControlForCallback(sc); return *this; } @@ -637,6 +762,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor } s->what |= layer_state_t::eColorTransformChanged; s->colorTransform = mat4(matrix, translation); + + registerSurfaceControlForCallback(sc); return *this; } diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h index cdc6a7e187..0a61cd1c9b 100644 --- a/libs/gui/include/gui/ITransactionCompletedListener.h +++ b/libs/gui/include/gui/ITransactionCompletedListener.h @@ -20,6 +20,7 @@ #include #include +#include namespace android { @@ -39,4 +40,21 @@ public: uint32_t flags = 0) override; }; +using CallbackId = int64_t; + +class ListenerCallbacks { +public: + ListenerCallbacks(const sp& listener, + const std::unordered_set& callbacks) + : transactionCompletedListener(listener), + callbackIds(callbacks.begin(), callbacks.end()) {} + + ListenerCallbacks(const sp& listener, + const std::vector& ids) + : transactionCompletedListener(listener), callbackIds(ids) {} + + sp transactionCompletedListener; + std::vector callbackIds; +}; + } // namespace android diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index e06e2b14b9..ddbac7bf47 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -74,6 +75,7 @@ struct layer_state_t { eApiChanged = 0x04000000, eSidebandStreamChanged = 0x08000000, eColorTransformChanged = 0x10000000, + eListenerCallbacksChanged = 0x20000000, }; layer_state_t() @@ -154,6 +156,8 @@ struct layer_state_t { int32_t api; sp sidebandStream; mat4 colorTransform; + + std::vector listenerCallbacks; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 8dcb8c9f33..2ed4f8f3e4 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -19,7 +19,9 @@ #include #include +#include #include +#include #include @@ -50,17 +52,29 @@ class Region; // --------------------------------------------------------------------------- +using TransactionCompletedCallback = std::function; +using TransactionCompletedCallbackWithContext = std::function; + class TransactionCompletedListener : public BnTransactionCompletedListener { - TransactionCompletedListener() = default; + TransactionCompletedListener(); + + CallbackId getNextIdLocked() REQUIRES(mMutex); std::mutex mMutex; bool mListening GUARDED_BY(mMutex) = false; + CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1; + + std::map mCallbacks GUARDED_BY(mMutex); + public: static sp getInstance(); + static sp getIInstance(); - void startListening(); + void startListeningLocked() REQUIRES(mMutex); + + CallbackId addCallback(const TransactionCompletedCallbackWithContext& callback); // Overrides BnTransactionCompletedListener's onTransactionCompleted void onTransactionCompleted() override; @@ -177,9 +191,27 @@ public: } }; + struct TCLHash { + std::size_t operator()(const sp& tcl) const { + return std::hash{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr); + } + }; + + struct CallbackInfo { + // All the callbacks that have been requested for a TransactionCompletedListener in the + // Transaction + std::unordered_set callbackIds; + // All the SurfaceControls that have been modified in this TransactionCompletedListener's + // process that require a callback if there is one or more callbackIds set. + std::unordered_set, SCHash> surfaceControls; + }; + class Transaction { std::unordered_map, ComposerState, SCHash> mComposerStates; SortedVector mDisplayStates; + std::unordered_map, CallbackInfo, TCLHash> + mListenerCallbacks; + uint32_t mForceSynchronous = 0; uint32_t mTransactionNestCount = 0; bool mAnimation = false; @@ -190,6 +222,8 @@ public: layer_state_t* getLayerState(const sp& sc); DisplayState& getDisplayState(const sp& token); + void registerSurfaceControlForCallback(const sp& sc); + public: Transaction() = default; virtual ~Transaction() = default; @@ -269,6 +303,9 @@ public: Transaction& setSidebandStream(const sp& sc, const sp& sidebandStream); + Transaction& addTransactionCompletedCallback(TransactionCompletedCallback callback, + void* callbackContext); + // Detaches all child surfaces (and their children recursively) // from their SurfaceControl. // The child SurfaceControls will not throw exceptions or return errors, -- cgit v1.2.3-59-g8ed1b From 9c0a1763cd293933f1773f8463daef1de5b8d08d Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Tue, 16 Oct 2018 13:32:31 -0700 Subject: [SurfaceFlinger] add getDisplayedContentSamplingAttributes i/f Add interface to ISurfaceComposer that can query the graphics.composer for querying the displayed content sampling engine's supported attributes. Bug: 116028618 Test: Boot Test: ran test client against prototype, see attributes reported Test: Ran new test './libgui_test --gtest_filter="DisplayedContentSamp*"' Test: on hwc with and without new function hook. Change-Id: Ie4bebd98d134e63a9f3e21f79ae519a1fe8055b0 --- libs/gui/ISurfaceComposer.cpp | 53 +++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 9 +++ libs/gui/include/gui/ISurfaceComposer.h | 8 +++ libs/gui/include/gui/SurfaceComposerClient.h | 5 ++ libs/gui/tests/Android.bp | 1 + libs/gui/tests/DisplayedContentSampling_test.cpp | 68 ++++++++++++++++++++++ libs/gui/tests/Surface_test.cpp | 6 ++ .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 27 +++++++++ .../surfaceflinger/DisplayHardware/ComposerHal.h | 6 ++ services/surfaceflinger/DisplayHardware/HWC2.cpp | 8 +++ services/surfaceflinger/DisplayHardware/HWC2.h | 3 + .../surfaceflinger/DisplayHardware/HWComposer.cpp | 14 +++++ .../surfaceflinger/DisplayHardware/HWComposer.h | 5 ++ services/surfaceflinger/SurfaceFlinger.cpp | 20 ++++++- services/surfaceflinger/SurfaceFlinger.h | 3 + .../unittests/mock/DisplayHardware/MockComposer.h | 2 + 16 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 libs/gui/tests/DisplayedContentSampling_test.cpp (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 69e5379047..80d435f67b 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -599,6 +599,43 @@ public: } return err; } + + virtual status_t getDisplayedContentSamplingAttributes(const sp& display, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const { + if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE; + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(display); + + status_t error = + remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, + data, &reply); + if (error != NO_ERROR) { + return error; + } + + uint32_t value = 0; + error = reply.readUint32(&value); + if (error != NO_ERROR) { + return error; + } + *outFormat = static_cast(value); + + error = reply.readUint32(&value); + if (error != NO_ERROR) { + return error; + } + *outDataspace = static_cast(value); + + error = reply.readUint32(&value); + if (error != NO_ERROR) { + return error; + } + *outComponentMask = static_cast(value); + return error; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -951,6 +988,22 @@ status_t BnSurfaceComposer::onTransact( } return result; } + case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + + sp display = data.readStrongBinder(); + ui::PixelFormat format; + ui::Dataspace dataspace; + uint8_t component = 0; + auto result = + getDisplayedContentSamplingAttributes(display, &format, &dataspace, &component); + if (result == NO_ERROR) { + reply->writeUint32(static_cast(format)); + reply->writeUint32(static_cast(dataspace)); + reply->writeUint32(static_cast(component)); + } + return result; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 87c6f27c57..41e5abbd0e 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1077,6 +1077,15 @@ status_t SurfaceComposerClient::getHdrCapabilities(const sp& display, outCapabilities); } +status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp& display, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) { + return ComposerService::getComposerService() + ->getDisplayedContentSamplingAttributes(display, outFormat, outDataspace, + outComponentMask); +} + // ---------------------------------------------------------------------------- status_t ScreenshotClient::capture(const sp& display, const ui::Dataspace reqDataSpace, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 761f31a04b..3b6c6e44b1 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -293,6 +293,13 @@ public: ui::PixelFormat* defaultPixelFormat, ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) const = 0; + /* + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t getDisplayedContentSamplingAttributes(const sp& display, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const = 0; }; // ---------------------------------------------------------------------------- @@ -332,6 +339,7 @@ public: CREATE_SCOPED_CONNECTION, GET_COMPOSITION_PREFERENCE, GET_COLOR_MANAGEMENT, + GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 10c27b1a33..cf55b6b33d 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -381,6 +381,11 @@ public: inline sp getClient() { return mClient; } + static status_t getDisplayedContentSamplingAttributes(const sp& display, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask); + private: virtual void onFirstRef(); diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index a6295e0387..6de641d0e0 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -17,6 +17,7 @@ cc_test { "BufferQueue_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", + "DisplayedContentSampling_test.cpp", "FillBuffer.cpp", "GLTest.cpp", "IGraphicBufferProducer_test.cpp", diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp new file mode 100644 index 0000000000..f2c0e0ca7f --- /dev/null +++ b/libs/gui/tests/DisplayedContentSampling_test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include + +namespace android { + +using Transaction = SurfaceComposerClient::Transaction; + +static constexpr uint32_t INVALID_MASK = 0x10; +class DisplayedContentSamplingTest : public ::testing::Test { +protected: + void SetUp() { + mComposerClient = new SurfaceComposerClient; + ASSERT_EQ(OK, mComposerClient->initCheck()); + mDisplayToken = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); + ASSERT_TRUE(mDisplayToken); + } + + bool shouldSkipTest(status_t status) { + if (status == PERMISSION_DENIED) { + SUCCEED() << "permissions denial, skipping test"; + return true; + } + if (status == INVALID_OPERATION) { + SUCCEED() << "optional function not supported, skipping test"; + return true; + } + return false; + } + + sp mComposerClient; + sp mDisplayToken; +}; + +TEST_F(DisplayedContentSamplingTest, GetDisplayedContentSamplingAttributesAreSane) { + ui::PixelFormat format; + ui::Dataspace dataspace; + uint8_t componentMask = 0; + status_t status = + mComposerClient->getDisplayedContentSamplingAttributes(mDisplayToken, &format, + &dataspace, &componentMask); + if (shouldSkipTest(status)) { + return; + } + EXPECT_EQ(OK, status); + EXPECT_LE(componentMask, INVALID_MASK); +} +} // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 4ba7da3560..3950bb6258 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -641,6 +641,12 @@ public: ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override { return NO_ERROR; } + status_t getDisplayedContentSamplingAttributes(const sp& /*display*/, + ui::PixelFormat* /*outFormat*/, + ui::Dataspace* /*outDataspace*/, + uint8_t* /*outComponentMask*/) const override { + return NO_ERROR; + } virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index f0bccaabf1..b919da73e2 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -1023,6 +1023,33 @@ Error Composer::setLayerColorTransform(Display display, Layer layer, const float return Error::NONE; } +Error Composer::getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat, + Dataspace* outDataspace, + uint8_t* outComponentMask) { + if (!outFormat || !outDataspace || !outComponentMask) { + return Error::BAD_PARAMETER; + } + if (!mClient_2_3) { + return Error::UNSUPPORTED; + } + Error error = kDefaultError; + mClient_2_3->getDisplayedContentSamplingAttributes(display, + [&](const auto tmpError, + const auto& tmpFormat, + const auto& tmpDataspace, + const auto& tmpComponentMask) { + error = tmpError; + if (error == Error::NONE) { + *outFormat = tmpFormat; + *outDataspace = tmpDataspace; + *outComponentMask = + static_cast( + tmpComponentMask); + } + }); + return error; +} + CommandReader::~CommandReader() { resetData(); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 4188352a76..c39171efa1 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -193,6 +193,9 @@ public: std::vector* outData) = 0; virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0; + virtual Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat, + Dataspace* outDataspace, + uint8_t* outComponentMask) = 0; }; namespace impl { @@ -392,6 +395,9 @@ public: Error getDisplayIdentificationData(Display display, uint8_t* outPort, std::vector* outData) override; Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override; + Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat, + Dataspace* outDataspace, + uint8_t* outComponentMask) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 393041d681..b4ac506c6b 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -538,6 +538,14 @@ Error Display::getHdrCapabilities(HdrCapabilities* outCapabilities) const return Error::None; } +Error Display::getDisplayedContentSamplingAttributes(PixelFormat* outFormat, + Dataspace* outDataspace, + uint8_t* outComponentMask) const { + auto intError = mComposer.getDisplayedContentSamplingAttributes(mId, outFormat, outDataspace, + outComponentMask); + return static_cast(intError); +} + Error Display::getReleaseFences( std::unordered_map>* outFences) const { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index d274631f9d..607d9ef718 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -237,6 +237,9 @@ public: [[clang::warn_unused_result]] Error supportsDoze(bool* outSupport) const; [[clang::warn_unused_result]] Error getHdrCapabilities( android::HdrCapabilities* outCapabilities) const; + [[clang::warn_unused_result]] Error getDisplayedContentSamplingAttributes( + android::ui::PixelFormat* outFormat, android::ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const; [[clang::warn_unused_result]] Error getReleaseFences( std::unordered_map>* outFences) const; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 9bbc37fe87..c93b4d6acd 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -733,6 +733,20 @@ mat4 HWComposer::getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace return matrix; } +status_t HWComposer::getDisplayedContentSamplingAttributes(DisplayId displayId, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) { + RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); + const auto error = + mDisplayData[displayId] + .hwcDisplay->getDisplayedContentSamplingAttributes(outFormat, outDataspace, + outComponentMask); + if (error == HWC2::Error::Unsupported) RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); + RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); + return NO_ERROR; +} + bool HWComposer::isUsingVrComposer() const { return getComposer()->isUsingVrComposer(); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 2f579077cc..1e5f971f83 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -125,6 +125,11 @@ public: mat4 getDataspaceSaturationMatrix(DisplayId displayId, ui::Dataspace dataspace); + // Returns the attributes of the color sampling engine. + status_t getDisplayedContentSamplingAttributes(DisplayId displayId, ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask); + // Events handling --------------------------------------------------------- // Returns stable display ID (and display name on connection of new or previously disconnected diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1db87915bc..6bd43aa598 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1114,6 +1114,23 @@ status_t SurfaceFlinger::getHdrCapabilities(const sp& displayToken, return NO_ERROR; } +status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp& displayToken, + ui::PixelFormat* outFormat, + ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const { + if (!outFormat || !outDataspace || !outComponentMask) { + return BAD_VALUE; + } + Mutex::Autolock _l(mStateLock); + const auto display = getDisplayDeviceLocked(displayToken); + if (!display || !display->getId()) { + ALOGE("getDisplayedContentSamplingAttributes: Bad display token: %p", display.get()); + return BAD_VALUE; + } + return getHwComposer().getDisplayedContentSamplingAttributes(*display->getId(), outFormat, + outDataspace, outComponentMask); +} + status_t SurfaceFlinger::enableVSyncInjections(bool enable) { postMessageSync(new LambdaMessage([&] { Mutex::Autolock _l(mStateLock); @@ -4725,7 +4742,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_ACTIVE_CONFIG: case SET_ACTIVE_COLOR_MODE: case INJECT_VSYNC: - case SET_POWER_MODE: { + case SET_POWER_MODE: + case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: { if (!callingThreadHasUnscopedSurfaceFlingerAccess()) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4a14de7f73..18accee837 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -480,6 +480,9 @@ private: status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, ui::Dataspace* outWideColorGamutDataspace, ui::PixelFormat* outWideColorGamutPixelFormat) const override; + virtual status_t getDisplayedContentSamplingAttributes( + const sp& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, + uint8_t* outComponentMask) const override; /* ------------------------------------------------------------------------ * DeathRecipient interface diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index c0395c01ce..03ef2f830e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -113,6 +113,8 @@ public: MOCK_METHOD4(setLayerInfo, Error(Display, Layer, uint32_t, uint32_t)); MOCK_METHOD3(getRenderIntents, Error(Display, ColorMode, std::vector*)); MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*)); + MOCK_METHOD4(getDisplayedContentSamplingAttributes, + Error(Display, PixelFormat*, Dataspace*, uint8_t*)); }; } // namespace mock -- cgit v1.2.3-59-g8ed1b From 74e53776ddca1b658589a59e29b226e1afb3f2fa Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Mon, 19 Nov 2018 10:52:38 -0800 Subject: [SurfaceFlinger] add setDisplayContentSamplingEnabled i/f Add interface to ISurfaceComposer that can enable or disable the graphics.composer's collection of the displayed content statistics. Bug: 116028618 Test: Boot Test: ran test client against prototype, see enable/disable working. Test: Ran new tests './libgui_test --gtest_filter="DisplayedContentSamp*"' Test: on hwc with and without new function hook. Change-Id: Ifb487e2bfbd8e0db6178ccbf762aa968c34576b9 --- libs/gui/ISurfaceComposer.cpp | 51 ++++++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 8 ++++ libs/gui/include/gui/ISurfaceComposer.h | 9 ++++ libs/gui/include/gui/SurfaceComposerClient.h | 2 + libs/gui/tests/DisplayedContentSampling_test.cpp | 49 ++++++++++++++++++--- libs/gui/tests/Surface_test.cpp | 5 +++ .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 12 +++++ .../surfaceflinger/DisplayHardware/ComposerHal.h | 4 ++ services/surfaceflinger/DisplayHardware/HWC2.cpp | 7 +++ services/surfaceflinger/DisplayHardware/HWC2.h | 3 ++ .../surfaceflinger/DisplayHardware/HWComposer.cpp | 14 ++++++ .../surfaceflinger/DisplayHardware/HWComposer.h | 2 + services/surfaceflinger/SurfaceFlinger.cpp | 19 ++++++-- services/surfaceflinger/SurfaceFlinger.h | 3 ++ .../unittests/mock/DisplayHardware/MockComposer.h | 1 + 15 files changed, 181 insertions(+), 8 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 80d435f67b..7d2615166f 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -636,6 +636,21 @@ public: *outComponentMask = static_cast(value); return error; } + + virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, + uint8_t componentMask, + uint64_t maxFrames) const { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(display); + data.writeBool(enable); + data.writeByte(static_cast(componentMask)); + data.writeUint64(maxFrames); + status_t result = + remote()->transact(BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED, data, + &reply); + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1004,6 +1019,42 @@ status_t BnSurfaceComposer::onTransact( } return result; } + case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + + sp display = nullptr; + bool enable = false; + int8_t componentMask = 0; + uint64_t maxFrames = 0; + status_t result = data.readStrongBinder(&display); + if (result != NO_ERROR) { + ALOGE("setDisplayContentSamplingEnabled failure in reading Display token: %d", + result); + return result; + } + + result = data.readBool(&enable); + if (result != NO_ERROR) { + ALOGE("setDisplayContentSamplingEnabled failure in reading enable: %d", result); + return result; + } + + result = data.readByte(static_cast(&componentMask)); + if (result != NO_ERROR) { + ALOGE("setDisplayContentSamplingEnabled failure in reading component mask: %d", + result); + return result; + } + + result = data.readUint64(&maxFrames); + if (result != NO_ERROR) { + ALOGE("setDisplayContentSamplingEnabled failure in reading max frames: %d", result); + return result; + } + + return setDisplayContentSamplingEnabled(display, enable, + static_cast(componentMask), maxFrames); + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9dfccc799e..405d2287be 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1098,6 +1098,14 @@ status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp& display, + bool enable, uint8_t componentMask, + uint64_t maxFrames) { + return ComposerService::getComposerService()->setDisplayContentSamplingEnabled(display, enable, + componentMask, + maxFrames); +} + // ---------------------------------------------------------------------------- status_t ScreenshotClient::capture(const sp& display, const ui::Dataspace reqDataSpace, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 3b6c6e44b1..41369c855a 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -300,6 +300,14 @@ public: ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) const = 0; + + /* Turns on the color sampling engine on the display. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, + uint8_t componentMask, + uint64_t maxFrames) const = 0; }; // ---------------------------------------------------------------------------- @@ -340,6 +348,7 @@ public: GET_COMPOSITION_PREFERENCE, GET_COLOR_MANAGEMENT, GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, + SET_DISPLAY_CONTENT_SAMPLING_ENABLED, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 7d0551289e..ba943a0f8e 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -386,6 +386,8 @@ public: ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask); + static status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, + uint8_t componentMask, uint64_t maxFrames); private: virtual void onFirstRef(); diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp index f2c0e0ca7f..f9d5dd632b 100644 --- a/libs/gui/tests/DisplayedContentSampling_test.cpp +++ b/libs/gui/tests/DisplayedContentSampling_test.cpp @@ -36,7 +36,12 @@ protected: ASSERT_TRUE(mDisplayToken); } - bool shouldSkipTest(status_t status) { + bool shouldSkipTest() { + ui::PixelFormat format; + ui::Dataspace dataspace; + status_t status = + mComposerClient->getDisplayedContentSamplingAttributes(mDisplayToken, &format, + &dataspace, &componentMask); if (status == PERMISSION_DENIED) { SUCCEED() << "permissions denial, skipping test"; return true; @@ -50,19 +55,53 @@ protected: sp mComposerClient; sp mDisplayToken; + uint8_t componentMask = 0; }; TEST_F(DisplayedContentSamplingTest, GetDisplayedContentSamplingAttributesAreSane) { + // tradefed infrastructure does not support use of GTEST_SKIP + if (shouldSkipTest()) return; + ui::PixelFormat format; ui::Dataspace dataspace; - uint8_t componentMask = 0; status_t status = mComposerClient->getDisplayedContentSamplingAttributes(mDisplayToken, &format, &dataspace, &componentMask); - if (shouldSkipTest(status)) { - return; - } EXPECT_EQ(OK, status); EXPECT_LE(componentMask, INVALID_MASK); } + +TEST_F(DisplayedContentSamplingTest, EnableWithInvalidMaskReturnsBadValue) { + if (shouldSkipTest()) return; + + status_t status = + mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true, INVALID_MASK, 0); + EXPECT_EQ(BAD_VALUE, status); +} + +TEST_F(DisplayedContentSamplingTest, EnableAndDisableSucceed) { + if (shouldSkipTest()) return; + + status_t status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true, + componentMask, 10); + EXPECT_EQ(OK, status); + + status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, false, componentMask, + 0); + EXPECT_EQ(OK, status); +} + +TEST_F(DisplayedContentSamplingTest, SelectivelyDisableComponentOk) { + if (shouldSkipTest()) return; + + status_t status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, true, + componentMask, 0); + EXPECT_EQ(OK, status); + + // Clear the lowest bit. + componentMask &= (componentMask - 1); + status = mComposerClient->setDisplayContentSamplingEnabled(mDisplayToken, false, componentMask, + 0); + EXPECT_EQ(OK, status); +} } // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 3950bb6258..cb1756f15b 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -647,6 +647,11 @@ public: uint8_t* /*outComponentMask*/) const override { return NO_ERROR; } + status_t setDisplayContentSamplingEnabled(const sp& /*display*/, bool /*enable*/, + uint8_t /*componentMask*/, + uint64_t /*maxFrames*/) const override { + return NO_ERROR; + } virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; } diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 5b641a23aa..3b7ed155ba 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -1067,6 +1067,18 @@ Error Composer::getDisplayCapabilities(Display display, return error; } +Error Composer::setDisplayContentSamplingEnabled(Display display, bool enabled, + uint8_t componentMask, uint64_t maxFrames) { + if (!mClient_2_3) { + return Error::UNSUPPORTED; + } + + auto enable = enabled ? V2_3::IComposerClient::DisplayedContentSampling::ENABLE + : V2_3::IComposerClient::DisplayedContentSampling::DISABLE; + return mClient_2_3->setDisplayedContentSamplingEnabled(display, enable, componentMask, + maxFrames); +} + CommandReader::~CommandReader() { resetData(); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 61af34892b..0db12a16cf 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -192,6 +192,8 @@ public: virtual Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat, Dataspace* outDataspace, uint8_t* outComponentMask) = 0; + virtual Error setDisplayContentSamplingEnabled(Display display, bool enabled, + uint8_t componentMask, uint64_t maxFrames) = 0; virtual Error getDisplayCapabilities(Display display, std::vector* outCapabilities) = 0; }; @@ -396,6 +398,8 @@ public: Error getDisplayedContentSamplingAttributes(Display display, PixelFormat* outFormat, Dataspace* outDataspace, uint8_t* outComponentMask) override; + Error setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask, + uint64_t maxFrames) override; Error getDisplayCapabilities(Display display, std::vector* outCapabilities) override; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 2df2d3b5b9..733a5dae43 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -555,6 +555,13 @@ Error Display::getDisplayedContentSamplingAttributes(PixelFormat* outFormat, return static_cast(intError); } +Error Display::setDisplayContentSamplingEnabled(bool enabled, uint8_t componentMask, + uint64_t maxFrames) const { + auto intError = + mComposer.setDisplayContentSamplingEnabled(mId, enabled, componentMask, maxFrames); + return static_cast(intError); +} + Error Display::getReleaseFences( std::unordered_map>* outFences) const { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 8c0f50c068..2d65051dff 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -240,6 +240,9 @@ public: [[clang::warn_unused_result]] Error getDisplayedContentSamplingAttributes( android::ui::PixelFormat* outFormat, android::ui::Dataspace* outDataspace, uint8_t* outComponentMask) const; + [[clang::warn_unused_result]] Error setDisplayContentSamplingEnabled(bool enabled, + uint8_t componentMask, + uint64_t maxFrames) const; [[clang::warn_unused_result]] Error getReleaseFences( std::unordered_map>* outFences) const; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index a752a7da4b..b27344d48e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -756,6 +756,20 @@ status_t HWComposer::getDisplayedContentSamplingAttributes(DisplayId displayId, return NO_ERROR; } +status_t HWComposer::setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled, + uint8_t componentMask, uint64_t maxFrames) { + RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); + const auto error = + mDisplayData[displayId].hwcDisplay->setDisplayContentSamplingEnabled(enabled, + componentMask, + maxFrames); + + if (error == HWC2::Error::Unsupported) RETURN_IF_HWC_ERROR(error, displayId, INVALID_OPERATION); + if (error == HWC2::Error::BadParameter) RETURN_IF_HWC_ERROR(error, displayId, BAD_VALUE); + RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); + return NO_ERROR; +} + bool HWComposer::isUsingVrComposer() const { return getComposer()->isUsingVrComposer(); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 0375f7489d..3f1328e90e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -131,6 +131,8 @@ public: status_t getDisplayedContentSamplingAttributes(DisplayId displayId, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask); + status_t setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled, + uint8_t componentMask, uint64_t maxFrames); // Events handling --------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5b3c47713e..75363bf874 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1121,8 +1121,7 @@ status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp if (!outFormat || !outDataspace || !outComponentMask) { return BAD_VALUE; } - Mutex::Autolock _l(mStateLock); - const auto display = getDisplayDeviceLocked(displayToken); + const auto display = getDisplayDevice(displayToken); if (!display || !display->getId()) { ALOGE("getDisplayedContentSamplingAttributes: Bad display token: %p", display.get()); return BAD_VALUE; @@ -1131,6 +1130,19 @@ status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp outDataspace, outComponentMask); } +status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp& displayToken, + bool enable, uint8_t componentMask, + uint64_t maxFrames) const { + const auto display = getDisplayDevice(displayToken); + if (!display || !display->getId()) { + ALOGE("setDisplayContentSamplingEnabled: Bad display token: %p", display.get()); + return BAD_VALUE; + } + + return getHwComposer().setDisplayContentSamplingEnabled(*display->getId(), enable, + componentMask, maxFrames); +} + status_t SurfaceFlinger::enableVSyncInjections(bool enable) { postMessageSync(new LambdaMessage([&] { Mutex::Autolock _l(mStateLock); @@ -4776,7 +4788,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_ACTIVE_COLOR_MODE: case INJECT_VSYNC: case SET_POWER_MODE: - case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: { + case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: + case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: { if (!callingThreadHasUnscopedSurfaceFlingerAccess()) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index eff5fca95f..1dd6e23291 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -483,6 +483,9 @@ private: virtual status_t getDisplayedContentSamplingAttributes( const sp& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) const override; + virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, + uint8_t componentMask, + uint64_t maxFrames) const override; /* ------------------------------------------------------------------------ * DeathRecipient interface diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 5a46c26653..68fd8b4907 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -115,6 +115,7 @@ public: MOCK_METHOD3(setLayerColorTransform, Error(Display, Layer, const float*)); MOCK_METHOD4(getDisplayedContentSamplingAttributes, Error(Display, PixelFormat*, Dataspace*, uint8_t*)); + MOCK_METHOD4(setDisplayContentSamplingEnabled, Error(Display, bool, uint8_t, uint64_t)); MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector*)); }; -- cgit v1.2.3-59-g8ed1b From 1d4249acec3ee6a936f2400177a3316b60388057 Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Wed, 29 Aug 2018 10:45:14 -0700 Subject: [SurfaceFlinger] add getDisplayedContentSample i/f Add interface to ISurfaceComposer that can query the graphics.composer for statistics on the displayed pixel content. Bug: 116028618 Test: Boot Test: ran test client, see data collected Change-Id: Ide9b81b80c3399e7d648c7b611514e0d699120de --- libs/gui/ISurfaceComposer.cpp | 77 ++++++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 6 ++ libs/gui/include/gui/ISurfaceComposer.h | 12 +++- libs/gui/include/gui/SurfaceComposerClient.h | 4 ++ libs/gui/tests/DisplayedContentSampling_test.cpp | 15 +++++ libs/gui/tests/Surface_test.cpp | 5 ++ libs/ui/include/ui/DisplayedFrameStats.h | 41 ++++++++++++ libs/ui/include_vndk/ui/DisplayedFrameStats.h | 1 + .../surfaceflinger/DisplayHardware/ComposerHal.cpp | 25 +++++++ .../surfaceflinger/DisplayHardware/ComposerHal.h | 5 ++ services/surfaceflinger/DisplayHardware/HWC2.cpp | 6 ++ services/surfaceflinger/DisplayHardware/HWC2.h | 3 + .../surfaceflinger/DisplayHardware/HWComposer.cpp | 10 +++ .../surfaceflinger/DisplayHardware/HWComposer.h | 3 + services/surfaceflinger/SurfaceFlinger.cpp | 16 ++++- services/surfaceflinger/SurfaceFlinger.h | 3 + .../unittests/mock/DisplayHardware/MockComposer.h | 2 + 17 files changed, 232 insertions(+), 2 deletions(-) create mode 100644 libs/ui/include/ui/DisplayedFrameStats.h create mode 120000 libs/ui/include_vndk/ui/DisplayedFrameStats.h (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 7d2615166f..f1fefcc14b 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -651,6 +651,49 @@ public: &reply); return result; } + + virtual status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + uint64_t timestamp, + DisplayedFrameStats* outStats) const { + if (!outStats) return BAD_VALUE; + + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeStrongBinder(display); + data.writeUint64(maxFrames); + data.writeUint64(timestamp); + + status_t result = + remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE, data, &reply); + + if (result != NO_ERROR) { + return result; + } + + result = reply.readUint64(&outStats->numFrames); + if (result != NO_ERROR) { + return result; + } + + result = reply.readInt64Vector( + reinterpret_cast*>(&outStats->component_0_sample)); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt64Vector( + reinterpret_cast*>(&outStats->component_1_sample)); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt64Vector( + reinterpret_cast*>(&outStats->component_2_sample)); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt64Vector( + reinterpret_cast*>(&outStats->component_3_sample)); + return result; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1055,6 +1098,40 @@ status_t BnSurfaceComposer::onTransact( return setDisplayContentSamplingEnabled(display, enable, static_cast(componentMask), maxFrames); } + case GET_DISPLAYED_CONTENT_SAMPLE: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + + sp display = data.readStrongBinder(); + uint64_t maxFrames = 0; + uint64_t timestamp = 0; + + status_t result = data.readUint64(&maxFrames); + if (result != NO_ERROR) { + ALOGE("getDisplayedContentSample failure in reading max frames: %d", result); + return result; + } + + result = data.readUint64(×tamp); + if (result != NO_ERROR) { + ALOGE("getDisplayedContentSample failure in reading timestamp: %d", result); + return result; + } + + DisplayedFrameStats stats; + result = getDisplayedContentSample(display, maxFrames, timestamp, &stats); + if (result == NO_ERROR) { + reply->writeUint64(stats.numFrames); + reply->writeInt64Vector( + *reinterpret_cast*>(&stats.component_0_sample)); + reply->writeInt64Vector( + *reinterpret_cast*>(&stats.component_1_sample)); + reply->writeInt64Vector( + *reinterpret_cast*>(&stats.component_2_sample)); + reply->writeInt64Vector( + *reinterpret_cast*>(&stats.component_3_sample)); + } + return result; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 405d2287be..070b253a80 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1106,6 +1106,12 @@ status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp& display, + uint64_t maxFrames, uint64_t timestamp, + DisplayedFrameStats* outStats) { + return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames, + timestamp, outStats); +} // ---------------------------------------------------------------------------- status_t ScreenshotClient::capture(const sp& display, const ui::Dataspace reqDataSpace, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 41369c855a..3052c0b312 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -27,10 +27,11 @@ #include +#include #include -#include #include #include +#include #include @@ -308,6 +309,14 @@ public: virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, uint8_t componentMask, uint64_t maxFrames) const = 0; + + /* Returns statistics on the color profile of the last frame displayed for a given display + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + uint64_t timestamp, + DisplayedFrameStats* outStats) const = 0; }; // ---------------------------------------------------------------------------- @@ -349,6 +358,7 @@ public: GET_COLOR_MANAGEMENT, GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, SET_DISPLAY_CONTENT_SAMPLING_ENABLED, + GET_DISPLAYED_CONTENT_SAMPLE, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index ba943a0f8e..2b107aa520 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -389,6 +390,9 @@ public: static status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, uint8_t componentMask, uint64_t maxFrames); + static status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + uint64_t timestamp, DisplayedFrameStats* outStats); + private: virtual void onFirstRef(); diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp index f9d5dd632b..5443812bff 100644 --- a/libs/gui/tests/DisplayedContentSampling_test.cpp +++ b/libs/gui/tests/DisplayedContentSampling_test.cpp @@ -104,4 +104,19 @@ TEST_F(DisplayedContentSamplingTest, SelectivelyDisableComponentOk) { 0); EXPECT_EQ(OK, status); } + +TEST_F(DisplayedContentSamplingTest, SampleCollectionCoherentWithSupportMask) { + if (shouldSkipTest()) return; + + DisplayedFrameStats stats; + status_t status = mComposerClient->getDisplayedContentSample(mDisplayToken, 0, 0, &stats); + EXPECT_EQ(OK, status); + if (stats.numFrames <= 0) return; + + if (componentMask & (0x1 << 0)) EXPECT_NE(0, stats.component_0_sample.size()); + if (componentMask & (0x1 << 1)) EXPECT_NE(0, stats.component_1_sample.size()); + if (componentMask & (0x1 << 2)) EXPECT_NE(0, stats.component_2_sample.size()); + if (componentMask & (0x1 << 3)) EXPECT_NE(0, stats.component_3_sample.size()); +} + } // namespace android diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index cb1756f15b..d37b81096b 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -652,6 +652,11 @@ public: uint64_t /*maxFrames*/) const override { return NO_ERROR; } + status_t getDisplayedContentSample(const sp& /*display*/, uint64_t /*maxFrames*/, + uint64_t /*timestamp*/, + DisplayedFrameStats* /*outStats*/) const override { + return NO_ERROR; + } virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; } diff --git a/libs/ui/include/ui/DisplayedFrameStats.h b/libs/ui/include/ui/DisplayedFrameStats.h new file mode 100644 index 0000000000..7a70ea1f06 --- /dev/null +++ b/libs/ui/include/ui/DisplayedFrameStats.h @@ -0,0 +1,41 @@ +/* + * Copyright 2018 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 + +namespace android { + +struct DisplayedFrameStats { + /* The number of frames represented by this sample. */ + uint64_t numFrames = 0; + /* A histogram counting how many times a pixel of a given value was displayed onscreen for + * FORMAT_COMPONENT_0. The buckets of the histogram are evenly weighted, the number of buckets + * is device specific. eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that + * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels + * were displayed onscreen in range 0x40->0x7F, etc. + */ + std::vector component_0_sample = {}; + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_1. */ + std::vector component_1_sample = {}; + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_2. */ + std::vector component_2_sample = {}; + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_3. */ + std::vector component_3_sample = {}; +}; + +} // namespace android diff --git a/libs/ui/include_vndk/ui/DisplayedFrameStats.h b/libs/ui/include_vndk/ui/DisplayedFrameStats.h new file mode 120000 index 0000000000..6014e1954a --- /dev/null +++ b/libs/ui/include_vndk/ui/DisplayedFrameStats.h @@ -0,0 +1 @@ +../../include/ui/DisplayedFrameStats.h \ No newline at end of file diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp index 3b7ed155ba..d6237cbdfc 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp @@ -1079,6 +1079,31 @@ Error Composer::setDisplayContentSamplingEnabled(Display display, bool enabled, maxFrames); } +Error Composer::getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp, + DisplayedFrameStats* outStats) { + if (!outStats) { + return Error::BAD_PARAMETER; + } + if (!mClient_2_3) { + return Error::UNSUPPORTED; + } + Error error = kDefaultError; + mClient_2_3->getDisplayedContentSample(display, maxFrames, timestamp, + [&](const auto tmpError, auto tmpNumFrames, + const auto& tmpSamples0, const auto& tmpSamples1, + const auto& tmpSamples2, const auto& tmpSamples3) { + error = tmpError; + if (error == Error::NONE) { + outStats->numFrames = tmpNumFrames; + outStats->component_0_sample = tmpSamples0; + outStats->component_1_sample = tmpSamples1; + outStats->component_2_sample = tmpSamples2; + outStats->component_3_sample = tmpSamples3; + } + }); + return error; +} + CommandReader::~CommandReader() { resetData(); diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index 0db12a16cf..38ee7ad545 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -194,6 +195,8 @@ public: uint8_t* outComponentMask) = 0; virtual Error setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask, uint64_t maxFrames) = 0; + virtual Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp, + DisplayedFrameStats* outStats) = 0; virtual Error getDisplayCapabilities(Display display, std::vector* outCapabilities) = 0; }; @@ -400,6 +403,8 @@ public: uint8_t* outComponentMask) override; Error setDisplayContentSamplingEnabled(Display display, bool enabled, uint8_t componentMask, uint64_t maxFrames) override; + Error getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp, + DisplayedFrameStats* outStats) override; Error getDisplayCapabilities(Display display, std::vector* outCapabilities) override; diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 733a5dae43..d2aa4ad031 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -562,6 +562,12 @@ Error Display::setDisplayContentSamplingEnabled(bool enabled, uint8_t componentM return static_cast(intError); } +Error Display::getDisplayedContentSample(uint64_t maxFrames, uint64_t timestamp, + android::DisplayedFrameStats* outStats) const { + auto intError = mComposer.getDisplayedContentSample(mId, maxFrames, timestamp, outStats); + return static_cast(intError); +} + Error Display::getReleaseFences( std::unordered_map>* outFences) const { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 2d65051dff..f5cb97e061 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -40,6 +40,7 @@ #include "PowerAdvisor.h" namespace android { + struct DisplayedFrameStats; class Fence; class FloatRect; class GraphicBuffer; @@ -243,6 +244,8 @@ public: [[clang::warn_unused_result]] Error setDisplayContentSamplingEnabled(bool enabled, uint8_t componentMask, uint64_t maxFrames) const; + [[clang::warn_unused_result]] Error getDisplayedContentSample( + uint64_t maxFrames, uint64_t timestamp, android::DisplayedFrameStats* outStats) const; [[clang::warn_unused_result]] Error getReleaseFences( std::unordered_map>* outFences) const; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index b27344d48e..dc6faad414 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -770,6 +770,16 @@ status_t HWComposer::setDisplayContentSamplingEnabled(DisplayId displayId, bool return NO_ERROR; } +status_t HWComposer::getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames, + uint64_t timestamp, DisplayedFrameStats* outStats) { + RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); + const auto error = + mDisplayData[displayId].hwcDisplay->getDisplayedContentSample(maxFrames, timestamp, + outStats); + RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); + return NO_ERROR; +} + bool HWComposer::isUsingVrComposer() const { return getComposer()->isUsingVrComposer(); } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 3f1328e90e..4d0694ec2e 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -36,6 +36,7 @@ namespace android { +struct DisplayedFrameStats; class GraphicBuffer; class String8; class TestableSurfaceFlinger; @@ -133,6 +134,8 @@ public: uint8_t* outComponentMask); status_t setDisplayContentSamplingEnabled(DisplayId displayId, bool enabled, uint8_t componentMask, uint64_t maxFrames); + status_t getDisplayedContentSample(DisplayId displayId, uint64_t maxFrames, uint64_t timestamp, + DisplayedFrameStats* outStats); // Events handling --------------------------------------------------------- diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0bda020a8a..90eccd2fed 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1145,6 +1145,19 @@ status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp& dis componentMask, maxFrames); } +status_t SurfaceFlinger::getDisplayedContentSample(const sp& displayToken, + uint64_t maxFrames, uint64_t timestamp, + DisplayedFrameStats* outStats) const { + const auto display = getDisplayDevice(displayToken); + if (!display || !display->getId()) { + ALOGE("getDisplayContentSample: Bad display token: %p", displayToken.get()); + return BAD_VALUE; + } + + return getHwComposer().getDisplayedContentSample(*display->getId(), maxFrames, timestamp, + outStats); +} + status_t SurfaceFlinger::enableVSyncInjections(bool enable) { postMessageSync(new LambdaMessage([&] { Mutex::Autolock _l(mStateLock); @@ -4791,7 +4804,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case INJECT_VSYNC: case SET_POWER_MODE: case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: - case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: { + case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: + case GET_DISPLAYED_CONTENT_SAMPLE: { if (!callingThreadHasUnscopedSurfaceFlingerAccess()) { IPCThreadState* ipc = IPCThreadState::self(); ALOGE("Permission Denial: can't access SurfaceFlinger pid=%d, uid=%d", diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index fe2f1c2658..ba92a8f4db 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -486,6 +486,9 @@ private: virtual status_t setDisplayContentSamplingEnabled(const sp& display, bool enable, uint8_t componentMask, uint64_t maxFrames) const override; + virtual status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, + uint64_t timestamp, + DisplayedFrameStats* outStats) const override; /* ------------------------------------------------------------------------ * DeathRecipient interface diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 68fd8b4907..dfdda099b3 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -116,6 +116,8 @@ public: MOCK_METHOD4(getDisplayedContentSamplingAttributes, Error(Display, PixelFormat*, Dataspace*, uint8_t*)); MOCK_METHOD4(setDisplayContentSamplingEnabled, Error(Display, bool, uint8_t, uint64_t)); + MOCK_METHOD4(getDisplayedContentSample, + Error(Display, uint64_t, uint64_t, DisplayedFrameStats*)); MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector*)); }; -- cgit v1.2.3-59-g8ed1b From aa3da6a25800089b1472075f6c4f5b1e8883bc94 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Wed, 12 Dec 2018 02:48:43 -0800 Subject: [ISurfaceComposer] Fix wrong returned value. Previously we returned the value of data space as the value of pixel format by accident, this patch fixes it. BUG: 111436479 Test: Build, flash, boot and verify with demo app. Change-Id: If03a322210e666cf57aba3a0a4171137440dbc15 --- libs/gui/ISurfaceComposer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f1fefcc14b..bd943c120e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -1033,7 +1033,7 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(static_cast(defaultDataspace)); reply->writeInt32(static_cast(defaultPixelFormat)); reply->writeInt32(static_cast(wideColorGamutDataspace)); - reply->writeInt32(static_cast(wideColorGamutDataspace)); + reply->writeInt32(static_cast(wideColorGamutPixelFormat)); } return NO_ERROR; } -- cgit v1.2.3-59-g8ed1b From 1d4c6a66c209ed69ab374e28d8bab34809edb9de Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Wed, 12 Dec 2018 13:59:46 -0800 Subject: SF: clean up casting around histogram reporting Takes advantage of the new binder Uint64Vector send/receive capabilites to clean up a messy cast in the display histogram functionality. Fixes: 120504999 Test: boot Test: libgui_test --gtest_filter="DisplayedContent*" Change-Id: Ie8fe724d4d81999777e6ce1e8a610f55e0070d37 --- libs/gui/ISurfaceComposer.cpp | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f1fefcc14b..5cf05ae891 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -675,23 +675,19 @@ public: return result; } - result = reply.readInt64Vector( - reinterpret_cast*>(&outStats->component_0_sample)); + result = reply.readUint64Vector(&outStats->component_0_sample); if (result != NO_ERROR) { return result; } - result = reply.readInt64Vector( - reinterpret_cast*>(&outStats->component_1_sample)); + result = reply.readUint64Vector(&outStats->component_1_sample); if (result != NO_ERROR) { return result; } - result = reply.readInt64Vector( - reinterpret_cast*>(&outStats->component_2_sample)); + result = reply.readUint64Vector(&outStats->component_2_sample); if (result != NO_ERROR) { return result; } - result = reply.readInt64Vector( - reinterpret_cast*>(&outStats->component_3_sample)); + result = reply.readUint64Vector(&outStats->component_3_sample); return result; } }; @@ -1121,14 +1117,10 @@ status_t BnSurfaceComposer::onTransact( result = getDisplayedContentSample(display, maxFrames, timestamp, &stats); if (result == NO_ERROR) { reply->writeUint64(stats.numFrames); - reply->writeInt64Vector( - *reinterpret_cast*>(&stats.component_0_sample)); - reply->writeInt64Vector( - *reinterpret_cast*>(&stats.component_1_sample)); - reply->writeInt64Vector( - *reinterpret_cast*>(&stats.component_2_sample)); - reply->writeInt64Vector( - *reinterpret_cast*>(&stats.component_3_sample)); + reply->writeUint64Vector(stats.component_0_sample); + reply->writeUint64Vector(stats.component_1_sample); + reply->writeUint64Vector(stats.component_2_sample); + reply->writeUint64Vector(stats.component_3_sample); } return result; } -- cgit v1.2.3-59-g8ed1b From 713b63f3e6f397cd688c982ee5c2bb5e26fa9446 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Wed, 17 Oct 2018 15:42:43 -0700 Subject: blast: Queue transactions by applying client Do not update SurfaceFlinger until all the fences in a transaction have signaled. While waiting on the fences, place the transaction in a queue with other transactions that were applied by the same SurfaceComposerClient. Test: Transaction_test Bug: 80477568 Change-Id: I6b866bfa955d5eafef28016a0c5de7c3862f1837 --- libs/gui/ISurfaceComposer.cpp | 12 +- libs/gui/SurfaceComposerClient.cpp | 4 +- libs/gui/include/gui/ISurfaceComposer.h | 3 +- libs/gui/tests/Surface_test.cpp | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 75 +++- services/surfaceflinger/SurfaceFlinger.h | 24 +- services/surfaceflinger/tests/Android.bp | 1 + services/surfaceflinger/tests/BufferGenerator.cpp | 381 +++++++++++++++++++++ services/surfaceflinger/tests/BufferGenerator.h | 58 ++++ .../surfaceflinger/tests/BufferGeneratorShader.h | 355 +++++++++++++++++++ services/surfaceflinger/tests/Transaction_test.cpp | 323 ++++++++++++----- 11 files changed, 1136 insertions(+), 104 deletions(-) create mode 100644 services/surfaceflinger/tests/BufferGenerator.cpp create mode 100644 services/surfaceflinger/tests/BufferGenerator.h create mode 100644 services/surfaceflinger/tests/BufferGeneratorShader.h (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2d6be26903..799151ae87 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -73,11 +73,9 @@ public: return interface_cast(reply.readStrongBinder()); } - virtual void setTransactionState( - const Vector& state, - const Vector& displays, - uint32_t flags) - { + virtual void setTransactionState(const Vector& state, + const Vector& displays, uint32_t flags, + const sp& applyToken) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -92,6 +90,7 @@ public: } data.writeUint32(flags); + data.writeStrongBinder(applyToken); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -750,7 +749,8 @@ status_t BnSurfaceComposer::onTransact( } uint32_t stateFlags = data.readUint32(); - setTransactionState(state, displays, stateFlags); + sp applyToken = data.readStrongBinder(); + setTransactionState(state, displays, stateFlags, applyToken); return NO_ERROR; } case BOOT_FINISHED: { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 95862199eb..5b004e2805 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -264,7 +264,9 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { mAnimation = false; mEarlyWakeup = false; - sf->setTransactionState(composerStates, displayStates, flags); + sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + + sf->setTransactionState(composerStates, displayStates, flags, applyToken); mStatus = NO_ERROR; return NO_ERROR; } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 3052c0b312..8cb40e78ad 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -124,7 +124,8 @@ public: /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual void setTransactionState(const Vector& state, - const Vector& displays, uint32_t flags) = 0; + const Vector& displays, uint32_t flags, + const sp& applyToken) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 67afbd6a52..c56304fdd4 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -558,8 +558,8 @@ public: void destroyDisplay(const sp& /*display */) override {} sp getBuiltInDisplay(int32_t /*id*/) override { return nullptr; } void setTransactionState(const Vector& /*state*/, - const Vector& /*displays*/, uint32_t /*flags*/) - override {} + const Vector& /*displays*/, uint32_t /*flags*/, + const sp& /*applyToken*/) override {} void bootFinished() override {} bool authenticateSurfaceTexture( const sp& /*surface*/) const override { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4a93be6fb4..02cd9d9f61 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1568,11 +1568,23 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { bool SurfaceFlinger::handleMessageTransaction() { uint32_t transactionFlags = peekTransactionFlags(); + + // Apply any ready transactions in the queues if there are still transactions that have not been + // applied, wake up during the next vsync period and check again + bool transactionNeeded = false; + if (!flushTransactionQueues()) { + transactionNeeded = true; + } + if (transactionFlags) { handleTransaction(transactionFlags); - return true; } - return false; + + if (transactionNeeded) { + setTransactionFlags(eTransactionNeeded); + } + + return transactionFlags; } void SurfaceFlinger::handleMessageRefresh() { @@ -3314,6 +3326,26 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags, return old; } +bool SurfaceFlinger::flushTransactionQueues() { + Mutex::Autolock _l(mStateLock); + auto it = mTransactionQueues.begin(); + while (it != mTransactionQueues.end()) { + auto& [applyToken, transactionQueue] = *it; + + while (!transactionQueue.empty()) { + const auto& [states, displays, flags] = transactionQueue.front(); + if (composerStateContainsUnsignaledFences(states)) { + break; + } + applyTransactionState(states, displays, flags); + transactionQueue.pop(); + } + + it = (transactionQueue.empty()) ? mTransactionQueues.erase(it) : std::next(it, 1); + } + return mTransactionQueues.empty(); +} + bool SurfaceFlinger::containsAnyInvalidClientState(const Vector& states) { for (const ComposerState& state : states) { // Here we need to check that the interface we're given is indeed @@ -3336,19 +3368,44 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector& return false; } -void SurfaceFlinger::setTransactionState( - const Vector& states, - const Vector& displays, - uint32_t flags) -{ +bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector& states) { + for (const ComposerState& state : states) { + const layer_state_t& s = state.state; + if (!(s.what & layer_state_t::eAcquireFenceChanged)) { + continue; + } + if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) { + return true; + } + } + return false; +} + +void SurfaceFlinger::setTransactionState(const Vector& states, + const Vector& displays, uint32_t flags, + const sp& applyToken) { ATRACE_CALL(); Mutex::Autolock _l(mStateLock); - uint32_t transactionFlags = 0; if (containsAnyInvalidClientState(states)) { return; } + // If its TransactionQueue already has a pending TransactionState or if it is pending + if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() || + composerStateContainsUnsignaledFences(states)) { + mTransactionQueues[applyToken].emplace(states, displays, flags); + setTransactionFlags(eTransactionNeeded); + return; + } + + applyTransactionState(states, displays, flags); +} + +void SurfaceFlinger::applyTransactionState(const Vector& states, + const Vector& displays, uint32_t flags) { + uint32_t transactionFlags = 0; + if (flags & eAnimation) { // For window updates that are part of an animation we must wait for // previous animation "frames" to be handled. @@ -3938,7 +3995,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(state, displays, 0); + setTransactionState(state, displays, 0, nullptr); const auto display = getDisplayDevice(displayToken); if (!display) return; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index b1bfb3a08d..822bb18f99 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -442,7 +442,8 @@ private: virtual void destroyDisplay(const sp& displayToken); virtual sp getBuiltInDisplay(int32_t id); virtual void setTransactionState(const Vector& state, - const Vector& displays, uint32_t flags); + const Vector& displays, uint32_t flags, + const sp& applyToken); virtual void bootFinished(); virtual bool authenticateSurfaceTexture( const sp& bufferProducer) const; @@ -553,6 +554,10 @@ private: /* ------------------------------------------------------------------------ * Transactions */ + void applyTransactionState(const Vector& state, + const Vector& displays, uint32_t flags) + REQUIRES(mStateLock); + bool flushTransactionQueues(); uint32_t getTransactionFlags(uint32_t flags); uint32_t peekTransactionFlags(); // Can only be called from the main thread or with mStateLock held @@ -561,6 +566,7 @@ private: void latchAndReleaseBuffer(const sp& layer); void commitTransaction(); bool containsAnyInvalidClientState(const Vector& states); + bool composerStateContainsUnsignaledFences(const Vector& states); uint32_t setClientStateLocked(const ComposerState& composerState); uint32_t setDisplayStateLocked(const DisplayState& s); void setDestroyStateLocked(const ComposerState& composerState); @@ -965,6 +971,22 @@ private: uint32_t mTexturePoolSize = 0; std::vector mTexturePool; + struct IBinderHash { + std::size_t operator()(const sp& strongPointer) const { + return std::hash{}(strongPointer.get()); + } + }; + struct TransactionState { + TransactionState(const Vector& composerStates, + const Vector& displayStates, uint32_t transactionFlags) + : states(composerStates), displays(displayStates), flags(transactionFlags) {} + + Vector states; + Vector displays; + uint32_t flags; + }; + std::unordered_map, std::queue, IBinderHash> mTransactionQueues; + /* ------------------------------------------------------------------------ * Feature prototyping */ diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 604aa7df56..f121a952d8 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -17,6 +17,7 @@ cc_test { defaults: ["surfaceflinger_defaults"], test_suites: ["device-tests"], srcs: [ + "BufferGenerator.cpp", "Credentials_test.cpp", "Stress_test.cpp", "SurfaceInterceptor_test.cpp", diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp new file mode 100644 index 0000000000..8ddda60cd2 --- /dev/null +++ b/services/surfaceflinger/tests/BufferGenerator.cpp @@ -0,0 +1,381 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include +#include +#include + +#include "BufferGenerator.h" +#include "BufferGeneratorShader.h" + +namespace android { + +/* Used to receive the surfaces and fences from egl. The egl buffers are thrown + * away. The fences are sent to the requester via a callback */ +class SurfaceManager { +public: + /* Returns a fence from egl */ + using BufferCallback = std::function& buffer, int32_t fence)>; + + /* Listens for a new frame, detaches the buffer and returns the fence + * through saved callback. */ + class BufferListener : public ConsumerBase::FrameAvailableListener { + public: + BufferListener(sp consumer, BufferCallback callback) + : mConsumer(consumer), mCallback(callback) {} + + void onFrameAvailable(const BufferItem& /*item*/) { + BufferItem item; + + if (mConsumer->acquireBuffer(&item, 0)) return; + if (mConsumer->detachBuffer(item.mSlot)) return; + + mCallback(item.mGraphicBuffer, item.mFence->dup()); + } + + private: + sp mConsumer; + BufferCallback mCallback; + }; + + /* Creates a buffer listener that waits on a new frame from the buffer + * queue. */ + void initialize(uint32_t width, uint32_t height, android_pixel_format_t format, + BufferCallback callback) { + sp producer; + sp consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + consumer->setDefaultBufferSize(width, height); + consumer->setDefaultBufferFormat(format); + + mBufferItemConsumer = new BufferItemConsumer(consumer, 0); + + mListener = new BufferListener(consumer, callback); + mBufferItemConsumer->setFrameAvailableListener(mListener); + + mSurface = new Surface(producer, true); + } + + /* Used by Egl manager. The surface is never displayed. */ + sp getSurface() const { return mSurface; } + +private: + sp mBufferItemConsumer; + sp mListener; + /* Used by Egl manager. The surface is never displayed */ + sp mSurface; +}; + +/* Used to generate valid fences. It is not possible to create a dummy sync + * fence for testing. Egl can generate buffers along with a valid fence. + * The buffer cannot be guaranteed to be the same format across all devices so + * a CPU filled buffer is used instead. The Egl fence is used along with the + * CPU filled buffer. */ +class EglManager { +public: + EglManager() + : mEglDisplay(EGL_NO_DISPLAY), mEglSurface(EGL_NO_SURFACE), mEglContext(EGL_NO_CONTEXT) {} + + ~EglManager() { cleanup(); } + + int initialize(sp surface) { + mSurface = surface; + + mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (mEglDisplay == EGL_NO_DISPLAY) return false; + + EGLint major; + EGLint minor; + if (!eglInitialize(mEglDisplay, &major, &minor)) { + ALOGW("Could not initialize EGL"); + return false; + } + + /* We're going to use a 1x1 pbuffer surface later on + * The configuration distance doesn't really matter for what we're + * trying to do */ + EGLint configAttrs[] = {EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_ALPHA_SIZE, + 0, + EGL_DEPTH_SIZE, + 24, + EGL_STENCIL_SIZE, + 0, + EGL_NONE}; + + EGLConfig configs[1]; + EGLint configCnt; + if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1, &configCnt)) { + ALOGW("Could not select EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + if (configCnt <= 0) { + ALOGW("Could not find EGL configuration"); + eglReleaseThread(); + eglTerminate(mEglDisplay); + return false; + } + + /* These objects are initialized below but the default "null" values are + * used to cleanup properly at any point in the initialization sequence */ + EGLint attrs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE}; + mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT, attrs); + if (mEglContext == EGL_NO_CONTEXT) { + ALOGW("Could not create EGL context"); + cleanup(); + return false; + } + + EGLint majorVersion; + if (!eglQueryContext(mEglDisplay, mEglContext, EGL_CONTEXT_CLIENT_VERSION, &majorVersion)) { + ALOGW("Could not query EGL version"); + cleanup(); + return false; + } + + if (majorVersion != 3) { + ALOGW("Unsupported EGL version"); + cleanup(); + return false; + } + + EGLint surfaceAttrs[] = {EGL_NONE}; + mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0], mSurface.get(), surfaceAttrs); + if (mEglSurface == EGL_NO_SURFACE) { + ALOGW("Could not create EGL surface"); + cleanup(); + return false; + } + + if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + ALOGW("Could not change current EGL context"); + cleanup(); + return false; + } + + return true; + } + + void makeCurrent() const { eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext); } + + void present() const { eglSwapBuffers(mEglDisplay, mEglSurface); } + +private: + void cleanup() { + if (mEglDisplay == EGL_NO_DISPLAY) return; + if (mEglSurface != EGL_NO_SURFACE) eglDestroySurface(mEglDisplay, mEglSurface); + if (mEglContext != EGL_NO_CONTEXT) eglDestroyContext(mEglDisplay, mEglContext); + + eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglReleaseThread(); + eglTerminate(mEglDisplay); + } + + sp mSurface; + EGLDisplay mEglDisplay; + EGLSurface mEglSurface; + EGLContext mEglContext; +}; + +class Program { +public: + ~Program() { + if (mInitialized) { + glDetachShader(mProgram, mVertexShader); + glDetachShader(mProgram, mFragmentShader); + + glDeleteShader(mVertexShader); + glDeleteShader(mFragmentShader); + + glDeleteProgram(mProgram); + } + } + + bool initialize(const char* vertex, const char* fragment) { + mVertexShader = buildShader(vertex, GL_VERTEX_SHADER); + if (!mVertexShader) { + return false; + } + + mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); + if (!mFragmentShader) { + return false; + } + + mProgram = glCreateProgram(); + glAttachShader(mProgram, mVertexShader); + glAttachShader(mProgram, mFragmentShader); + + glLinkProgram(mProgram); + + GLint status; + glGetProgramiv(mProgram, GL_LINK_STATUS, &status); + if (status != GL_TRUE) { + GLint length = 0; + glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &length); + if (length > 1) { + GLchar log[length]; + glGetProgramInfoLog(mProgram, length, nullptr, &log[0]); + ALOGE("%s", log); + } + ALOGE("Error while linking shaders"); + return false; + } + mInitialized = true; + return true; + } + + void use() const { glUseProgram(mProgram); } + + void bindVec4(GLint location, vec4 v) const { glUniform4f(location, v.x, v.y, v.z, v.w); } + + void bindVec3(GLint location, const vec3* v, uint32_t count) const { + glUniform3fv(location, count, &(v->x)); + } + + void bindFloat(GLint location, float v) { glUniform1f(location, v); } + +private: + GLuint buildShader(const char* source, GLenum type) const { + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, nullptr); + glCompileShader(shader); + + GLint status; + glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (status != GL_TRUE) { + ALOGE("Error while compiling shader of type 0x%x:\n===\n%s\n===", type, source); + // Some drivers return wrong values for GL_INFO_LOG_LENGTH + // use a fixed size instead + GLchar log[512]; + glGetShaderInfoLog(shader, sizeof(log), nullptr, &log[0]); + ALOGE("Shader info log: %s", log); + return 0; + } + + return shader; + } + + GLuint mProgram = 0; + GLuint mVertexShader = 0; + GLuint mFragmentShader = 0; + bool mInitialized = false; +}; + +BufferGenerator::BufferGenerator() + : mSurfaceManager(new SurfaceManager), mEglManager(new EglManager), mProgram(new Program) { + const float width = 1000.0; + const float height = 1000.0; + + auto setBufferWithContext = + std::bind(setBuffer, std::placeholders::_1, std::placeholders::_2, this); + mSurfaceManager->initialize(width, height, HAL_PIXEL_FORMAT_RGBA_8888, setBufferWithContext); + + if (!mEglManager->initialize(mSurfaceManager->getSurface())) return; + + mEglManager->makeCurrent(); + + if (!mProgram->initialize(VERTEX_SHADER, FRAGMENT_SHADER)) return; + mProgram->use(); + mProgram->bindVec4(0, vec4{width, height, 1.0f / width, 1.0f / height}); + mProgram->bindVec3(2, &SPHERICAL_HARMONICS[0], 4); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, &TRIANGLE[0]); + + mInitialized = true; +} + +BufferGenerator::~BufferGenerator() { + mEglManager->makeCurrent(); +} + +status_t BufferGenerator::get(sp* outBuffer, sp* outFence) { + // mMutex is used to protect get() from getting called by multiple threads at the same time + static std::mutex mMutex; + std::lock_guard lock(mMutex); + + if (!mInitialized) { + if (outBuffer) { + *outBuffer = nullptr; + } + if (*outFence) { + *outFence = nullptr; + } + return -EINVAL; + } + + // Generate a buffer and fence. They will be returned through the setBuffer callback + mEglManager->makeCurrent(); + + glClear(GL_COLOR_BUFFER_BIT); + + const std::chrono::duration time = std::chrono::steady_clock::now() - mEpoch; + mProgram->bindFloat(1, time.count()); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + mPending = true; + mEglManager->present(); + + // Wait for the setBuffer callback + if (!mConditionVariable.wait_for(mMutex, std::chrono::seconds(2), + [this] { return !mPending; })) { + ALOGE("failed to set buffer and fence"); + return -ETIME; + } + + // Return buffer and fence + if (outBuffer) { + *outBuffer = mGraphicBuffer; + } + if (outFence) { + *outFence = new Fence(mFence); + } else { + close(mFence); + } + mGraphicBuffer = nullptr; + mFence = -1; + + return NO_ERROR; +} + +// static +void BufferGenerator::setBuffer(const sp& buffer, int32_t fence, + void* bufferGenerator) { + BufferGenerator* generator = static_cast(bufferGenerator); + generator->mGraphicBuffer = buffer; + generator->mFence = fence; + generator->mPending = false; + generator->mConditionVariable.notify_all(); +} + +} // namespace android diff --git a/services/surfaceflinger/tests/BufferGenerator.h b/services/surfaceflinger/tests/BufferGenerator.h new file mode 100644 index 0000000000..a3ffe86572 --- /dev/null +++ b/services/surfaceflinger/tests/BufferGenerator.h @@ -0,0 +1,58 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace android { + +class SurfaceManager; +class EglManager; +class Program; + +class BufferGenerator { +public: + BufferGenerator(); + ~BufferGenerator(); + + /* Get a new fence */ + status_t get(sp* outBuffer, sp* outFence); + + /* Static callback that sets the fence on a particular instance */ + static void setBuffer(const sp& buffer, int32_t fence, void* fenceGenerator); + +private: + bool mInitialized = false; + + std::unique_ptr mSurfaceManager; + std::unique_ptr mEglManager; + std::unique_ptr mProgram; + + std::condition_variable_any mConditionVariable; + + sp mGraphicBuffer; + int32_t mFence = -1; + bool mPending = false; + + using Epoch = std::chrono::time_point; + Epoch mEpoch = std::chrono::steady_clock::now(); +}; + +} // namespace android diff --git a/services/surfaceflinger/tests/BufferGeneratorShader.h b/services/surfaceflinger/tests/BufferGeneratorShader.h new file mode 100644 index 0000000000..564cda3ccc --- /dev/null +++ b/services/surfaceflinger/tests/BufferGeneratorShader.h @@ -0,0 +1,355 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +static const char* VERTEX_SHADER = R"SHADER__(#version 300 es +precision highp float; + +layout(location = 0) in vec4 mesh_position; + +void main() { + gl_Position = mesh_position; +} +)SHADER__"; + +static const char* FRAGMENT_SHADER = R"SHADER__(#version 300 es +precision highp float; + +layout(location = 0) uniform vec4 resolution; +layout(location = 1) uniform float time; +layout(location = 2) uniform vec3[4] SPHERICAL_HARMONICS; + +layout(location = 0) out vec4 fragColor; + +#define saturate(x) clamp(x, 0.0, 1.0) +#define PI 3.14159265359 + +//------------------------------------------------------------------------------ +// Distance field functions +//------------------------------------------------------------------------------ + +float sdPlane(in vec3 p) { + return p.y; +} + +float sdSphere(in vec3 p, float s) { + return length(p) - s; +} + +float sdTorus(in vec3 p, in vec2 t) { + return length(vec2(length(p.xz) - t.x, p.y)) - t.y; +} + +vec2 opUnion(vec2 d1, vec2 d2) { + return d1.x < d2.x ? d1 : d2; +} + +vec2 scene(in vec3 position) { + vec2 scene = opUnion( + vec2(sdPlane(position), 1.0), + vec2(sdSphere(position - vec3(0.0, 0.4, 0.0), 0.4), 12.0) + ); + return scene; +} + +//------------------------------------------------------------------------------ +// Ray casting +//------------------------------------------------------------------------------ + +float shadow(in vec3 origin, in vec3 direction, in float tmin, in float tmax) { + float hit = 1.0; + + for (float t = tmin; t < tmax; ) { + float h = scene(origin + direction * t).x; + if (h < 0.001) return 0.0; + t += h; + hit = min(hit, 10.0 * h / t); + } + + return clamp(hit, 0.0, 1.0); +} + +vec2 traceRay(in vec3 origin, in vec3 direction) { + float tmin = 0.02; + float tmax = 20.0; + + float material = -1.0; + float t = tmin; + + for ( ; t < tmax; ) { + vec2 hit = scene(origin + direction * t); + if (hit.x < 0.002 || t > tmax) break; + t += hit.x; + material = hit.y; + } + + if (t > tmax) { + material = -1.0; + } + + return vec2(t, material); +} + +vec3 normal(in vec3 position) { + vec3 epsilon = vec3(0.001, 0.0, 0.0); + vec3 n = vec3( + scene(position + epsilon.xyy).x - scene(position - epsilon.xyy).x, + scene(position + epsilon.yxy).x - scene(position - epsilon.yxy).x, + scene(position + epsilon.yyx).x - scene(position - epsilon.yyx).x); + return normalize(n); +} + +//------------------------------------------------------------------------------ +// BRDF +//------------------------------------------------------------------------------ + +float pow5(float x) { + float x2 = x * x; + return x2 * x2 * x; +} + +float D_GGX(float linearRoughness, float NoH, const vec3 h) { + // Walter et al. 2007, "Microfacet Models for Refraction through Rough Surfaces" + float oneMinusNoHSquared = 1.0 - NoH * NoH; + float a = NoH * linearRoughness; + float k = linearRoughness / (oneMinusNoHSquared + a * a); + float d = k * k * (1.0 / PI); + return d; +} + +float V_SmithGGXCorrelated(float linearRoughness, float NoV, float NoL) { + // Heitz 2014, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs" + float a2 = linearRoughness * linearRoughness; + float GGXV = NoL * sqrt((NoV - a2 * NoV) * NoV + a2); + float GGXL = NoV * sqrt((NoL - a2 * NoL) * NoL + a2); + return 0.5 / (GGXV + GGXL); +} + +vec3 F_Schlick(const vec3 f0, float VoH) { + // Schlick 1994, "An Inexpensive BRDF Model for Physically-Based Rendering" + return f0 + (vec3(1.0) - f0) * pow5(1.0 - VoH); +} + +float F_Schlick(float f0, float f90, float VoH) { + return f0 + (f90 - f0) * pow5(1.0 - VoH); +} + +float Fd_Burley(float linearRoughness, float NoV, float NoL, float LoH) { + // Burley 2012, "Physically-Based Shading at Disney" + float f90 = 0.5 + 2.0 * linearRoughness * LoH * LoH; + float lightScatter = F_Schlick(1.0, f90, NoL); + float viewScatter = F_Schlick(1.0, f90, NoV); + return lightScatter * viewScatter * (1.0 / PI); +} + +float Fd_Lambert() { + return 1.0 / PI; +} + +//------------------------------------------------------------------------------ +// Indirect lighting +//------------------------------------------------------------------------------ + +vec3 Irradiance_SphericalHarmonics(const vec3 n) { + return max( + SPHERICAL_HARMONICS[0] + + SPHERICAL_HARMONICS[1] * (n.y) + + SPHERICAL_HARMONICS[2] * (n.z) + + SPHERICAL_HARMONICS[3] * (n.x) + , 0.0); +} + +vec2 PrefilteredDFG_Karis(float roughness, float NoV) { + // Karis 2014, "Physically Based Material on Mobile" + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4( 1.0, 0.0425, 1.040, -0.040); + + vec4 r = roughness * c0 + c1; + float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y; + + return vec2(-1.04, 1.04) * a004 + r.zw; +} + +//------------------------------------------------------------------------------ +// Tone mapping and transfer functions +//------------------------------------------------------------------------------ + +vec3 Tonemap_ACES(const vec3 x) { + // Narkowicz 2015, "ACES Filmic Tone Mapping Curve" + const float a = 2.51; + const float b = 0.03; + const float c = 2.43; + const float d = 0.59; + const float e = 0.14; + return (x * (a * x + b)) / (x * (c * x + d) + e); +} + +vec3 OECF_sRGBFast(const vec3 linear) { + return pow(linear, vec3(1.0 / 2.2)); +} + +//------------------------------------------------------------------------------ +// Rendering +//------------------------------------------------------------------------------ + +vec3 render(in vec3 origin, in vec3 direction, out float distance) { + // Sky gradient + vec3 color = vec3(0.65, 0.85, 1.0) + direction.y * 0.72; + + // (distance, material) + vec2 hit = traceRay(origin, direction); + distance = hit.x; + float material = hit.y; + + // We've hit something in the scene + if (material > 0.0) { + vec3 position = origin + distance * direction; + + vec3 v = normalize(-direction); + vec3 n = normal(position); + vec3 l = normalize(vec3(0.6, 0.7, -0.7)); + vec3 h = normalize(v + l); + vec3 r = normalize(reflect(direction, n)); + + float NoV = abs(dot(n, v)) + 1e-5; + float NoL = saturate(dot(n, l)); + float NoH = saturate(dot(n, h)); + float LoH = saturate(dot(l, h)); + + vec3 baseColor = vec3(0.0); + float roughness = 0.0; + float metallic = 0.0; + + float intensity = 2.0; + float indirectIntensity = 0.64; + + if (material < 4.0) { + // Checkerboard floor + float f = mod(floor(6.0 * position.z) + floor(6.0 * position.x), 2.0); + baseColor = 0.4 + f * vec3(0.6); + roughness = 0.1; + } else if (material < 16.0) { + // Metallic objects + baseColor = vec3(0.3, 0.0, 0.0); + roughness = 0.2; + } + + float linearRoughness = roughness * roughness; + vec3 diffuseColor = (1.0 - metallic) * baseColor.rgb; + vec3 f0 = 0.04 * (1.0 - metallic) + baseColor.rgb * metallic; + + float attenuation = shadow(position, l, 0.02, 2.5); + + // specular BRDF + float D = D_GGX(linearRoughness, NoH, h); + float V = V_SmithGGXCorrelated(linearRoughness, NoV, NoL); + vec3 F = F_Schlick(f0, LoH); + vec3 Fr = (D * V) * F; + + // diffuse BRDF + vec3 Fd = diffuseColor * Fd_Burley(linearRoughness, NoV, NoL, LoH); + + color = Fd + Fr; + color *= (intensity * attenuation * NoL) * vec3(0.98, 0.92, 0.89); + + // diffuse indirect + vec3 indirectDiffuse = Irradiance_SphericalHarmonics(n) * Fd_Lambert(); + + vec2 indirectHit = traceRay(position, r); + vec3 indirectSpecular = vec3(0.65, 0.85, 1.0) + r.y * 0.72; + if (indirectHit.y > 0.0) { + if (indirectHit.y < 4.0) { + vec3 indirectPosition = position + indirectHit.x * r; + // Checkerboard floor + float f = mod(floor(6.0 * indirectPosition.z) + floor(6.0 * indirectPosition.x), 2.0); + indirectSpecular = 0.4 + f * vec3(0.6); + } else if (indirectHit.y < 16.0) { + // Metallic objects + indirectSpecular = vec3(0.3, 0.0, 0.0); + } + } + + // indirect contribution + vec2 dfg = PrefilteredDFG_Karis(roughness, NoV); + vec3 specularColor = f0 * dfg.x + dfg.y; + vec3 ibl = diffuseColor * indirectDiffuse + indirectSpecular * specularColor; + + color += ibl * indirectIntensity; + } + + return color; +} + +//------------------------------------------------------------------------------ +// Setup and execution +//------------------------------------------------------------------------------ + +mat3 setCamera(in vec3 origin, in vec3 target, float rotation) { + vec3 forward = normalize(target - origin); + vec3 orientation = vec3(sin(rotation), cos(rotation), 0.0); + vec3 left = normalize(cross(forward, orientation)); + vec3 up = normalize(cross(left, forward)); + return mat3(left, up, forward); +} + +void main() { + // Normalized coordinates + vec2 p = -1.0 + 2.0 * gl_FragCoord.xy / resolution.xy; + // Aspect ratio + p.x *= resolution.x / resolution.y; + + // Camera position and "look at" + vec3 origin = vec3(0.0, 1.0, 0.0); + vec3 target = vec3(0.0); + + origin.x += 2.0 * cos(time * 0.2); + origin.z += 2.0 * sin(time * 0.2); + + mat3 toWorld = setCamera(origin, target, 0.0); + vec3 direction = toWorld * normalize(vec3(p.xy, 2.0)); + + // Render scene + float distance; + vec3 color = render(origin, direction, distance); + + // Tone mapping + color = Tonemap_ACES(color); + + // Exponential distance fog + color = mix(color, 0.8 * vec3(0.7, 0.8, 1.0), 1.0 - exp2(-0.011 * distance * distance)); + + // Gamma compression + color = OECF_sRGBFast(color); + + fragColor = vec4(color, 1.0); +} +)SHADER__"; + +static const android::vec3 SPHERICAL_HARMONICS[4] = + {{0.754554516862612, 0.748542953903366, 0.790921515418539}, + {-0.083856548007422, 0.092533500963210, 0.322764661032516}, + {0.308152705331738, 0.366796330467391, 0.466698181299906}, + {-0.188884931542396, -0.277402551592231, -0.377844212327557}}; + +static const android::vec4 TRIANGLE[3] = {{-1.0f, -1.0f, 1.0f, 1.0f}, + {3.0f, -1.0f, 1.0f, 1.0f}, + {-1.0f, 3.0f, 1.0f, 1.0f}}; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 037d32faff..d118ad6402 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -28,7 +28,6 @@ #include #include - #include #include #include @@ -41,6 +40,8 @@ #include #include +#include "BufferGenerator.h" + namespace android { namespace { @@ -478,6 +479,11 @@ protected: return screenshot; } + static status_t getBuffer(sp* outBuffer, sp* outFence) { + static BufferGenerator bufferGenerator; + return bufferGenerator.get(outBuffer, outFence); + } + sp mClient; sp mDisplay; @@ -2163,6 +2169,36 @@ TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) { } TEST_F(LayerTransactionTest, SetFenceBasic_BufferState) { + sp layer; + Transaction transaction; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + + sp buffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + + sp fence; + if (getBuffer(nullptr, &fence) != NO_ERROR) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply(); + + status_t status = fence->wait(1000); + ASSERT_NE(static_cast(Fence::Status::Unsignaled), status); + std::this_thread::sleep_for(200ms); + + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); +} + +TEST_F(LayerTransactionTest, SetFenceNull_BufferState) { sp layer; ASSERT_NO_FATAL_FAILURE( layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); @@ -2514,7 +2550,7 @@ public: } void addSurface(ExpectedResult::Transaction transactionResult, const sp& layer, - ExpectedResult::Buffer bufferResult = NOT_ACQUIRED, + ExpectedResult::Buffer bufferResult = ACQUIRED, ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { mTransactionResult = transactionResult; mExpectedSurfaceResults.emplace(std::piecewise_construct, @@ -2524,7 +2560,7 @@ public: void addSurfaces(ExpectedResult::Transaction transactionResult, const std::vector>& layers, - ExpectedResult::Buffer bufferResult = NOT_ACQUIRED, + ExpectedResult::Buffer bufferResult = ACQUIRED, ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) { for (const auto& layer : layers) { addSurface(transactionResult, layer, bufferResult, previousBufferResult); @@ -2631,24 +2667,22 @@ public: return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState); } - static void fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper, - const sp& layer = nullptr) { + static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper, + const sp& layer = nullptr) { if (layer) { - sp buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY | - BufferUsage::GPU_TEXTURE, - "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); - - sp fence = new Fence(-1); + sp buffer; + sp fence; + int err = getBuffer(&buffer, &fence); + if (err != NO_ERROR) { + return err; + } transaction.setBuffer(layer, buffer).setAcquireFence(layer, fence); } transaction.addTransactionCompletedCallback(callbackHelper->function, callbackHelper->getContext()); + return NO_ERROR; } static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult, @@ -2680,7 +2714,11 @@ TEST_F(LayerCallbackTest, Basic) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); @@ -2695,19 +2733,28 @@ TEST_F(LayerCallbackTest, NoBuffer) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); ExpectedResult expected; - expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); } TEST_F(LayerCallbackTest, NoStateChange) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); @@ -2721,7 +2768,11 @@ TEST_F(LayerCallbackTest, OffScreen) { Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply(); @@ -2737,8 +2788,16 @@ TEST_F(LayerCallbackTest, Merge) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -2756,8 +2815,16 @@ TEST_F(LayerCallbackTest, Merge_SameCallback) { Transaction transaction1, transaction2; CallbackHelper callback; - fillTransaction(transaction1, &callback, layer1); - fillTransaction(transaction2, &callback, layer2); + int err = fillTransaction(transaction1, &callback, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.merge(std::move(transaction1)).apply(); @@ -2773,8 +2840,16 @@ TEST_F(LayerCallbackTest, Merge_SameLayer) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer); - fillTransaction(transaction2, &callback2, layer); + int err = fillTransaction(transaction1, &callback1, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.merge(std::move(transaction1)).apply(); @@ -2784,25 +2859,6 @@ TEST_F(LayerCallbackTest, Merge_SameLayer) { EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true)); } -TEST_F(LayerCallbackTest, Merge_SingleBuffer) { - sp layer1, layer2; - ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer()); - ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer()); - - Transaction transaction1, transaction2; - CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2); - - transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); - transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); - - ExpectedResult expected; - expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}); - EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true)); - EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true)); -} - TEST_F(LayerCallbackTest, Merge_DifferentClients) { sp client1(new SurfaceComposerClient), client2(new SurfaceComposerClient); @@ -2818,8 +2874,16 @@ TEST_F(LayerCallbackTest, Merge_DifferentClients) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -2837,13 +2901,17 @@ TEST_F(LayerCallbackTest, MultipleTransactions) { Transaction transaction; CallbackHelper callback; for (size_t i = 0; i < 10; i++) { - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); ExpectedResult expected; expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, - ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::Buffer::ACQUIRED, (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED : ExpectedResult::PreviousBuffer::RELEASED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected)); @@ -2861,10 +2929,18 @@ TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) { ExpectedResult expected; if (i == 0) { - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); } else { - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } } transaction.apply(); @@ -2882,9 +2958,17 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { CallbackHelper callback; for (size_t i = 0; i < 10; i++) { if (i == 0) { - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } } else { - fillTransaction(transaction, &callback); + int err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); @@ -2892,7 +2976,9 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) { ExpectedResult expected; expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED : ExpectedResult::Transaction::NOT_PRESENTED, - layer); + layer, + (i == 0) ? ExpectedResult::Buffer::ACQUIRED + : ExpectedResult::Buffer::NOT_ACQUIRED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0)); } ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState()); @@ -2906,15 +2992,23 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; for (size_t i = 0; i < 10; i++) { - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, - ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::Buffer::ACQUIRED, (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED : ExpectedResult::PreviousBuffer::RELEASED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected)); @@ -2939,15 +3033,23 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) { Transaction transaction1, transaction2; CallbackHelper callback1, callback2; for (size_t i = 0; i < 10; i++) { - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); ExpectedResult expected; expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2}, - ExpectedResult::Buffer::NOT_ACQUIRED, + ExpectedResult::Buffer::ACQUIRED, (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED : ExpectedResult::PreviousBuffer::RELEASED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected)); @@ -2973,8 +3075,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha CallbackHelper callback1, callback2; // Normal call to set up test - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -2986,8 +3096,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateCha expected.reset(); // Test - fillTransaction(transaction1, &callback1); - fillTransaction(transaction2, &callback2); + err = fillTransaction(transaction1, &callback1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.merge(std::move(transaction1)).apply(); @@ -3012,8 +3130,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC CallbackHelper callback1, callback2; // Normal call to set up test - fillTransaction(transaction1, &callback1, layer1); - fillTransaction(transaction2, &callback2, layer2); + int err = fillTransaction(transaction1, &callback1, layer1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2, layer2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction1.setFrame(layer1, Rect(0, 0, 32, 32)); transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); @@ -3025,12 +3151,21 @@ TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateC expected.reset(); // Test - fillTransaction(transaction1, &callback1); - fillTransaction(transaction2, &callback2); + err = fillTransaction(transaction1, &callback1); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + err = fillTransaction(transaction2, &callback2); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply(); - expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2, + ExpectedResult::Buffer::NOT_ACQUIRED); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true)); EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true)); } @@ -3047,13 +3182,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) { for (auto& expected : expectedResults) { expected.reset(); expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer, - ExpectedResult::Buffer::NOT_ACQUIRED, previousBufferResult); + ExpectedResult::Buffer::ACQUIRED, previousBufferResult); previousBufferResult = ExpectedResult::PreviousBuffer::RELEASED; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.apply(); - std::this_thread::sleep_for(200ms); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } @@ -3062,23 +3200,33 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + // Normal call to set up test Transaction transaction; CallbackHelper callback; + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + transaction.apply(); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); + + // Test std::vector expectedResults(50); - bool first = true; for (auto& expected : expectedResults) { expected.reset(); - if (first) { - fillTransaction(transaction, &callback, layer); - expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); - first = false; - } else { - fillTransaction(transaction, &callback); + err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; } transaction.apply(); - std::this_thread::sleep_for(200ms); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } @@ -3090,7 +3238,11 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { // Normal call to set up test Transaction transaction; CallbackHelper callback; - fillTransaction(transaction, &callback, layer); + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); @@ -3102,13 +3254,16 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { std::vector expectedResults(50); for (auto& expected : expectedResults) { expected.reset(); - expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer); + expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer, + ExpectedResult::Buffer::NOT_ACQUIRED); - fillTransaction(transaction, &callback); + err = fillTransaction(transaction, &callback); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply(); - - std::this_thread::sleep_for(200ms); } EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } -- cgit v1.2.3-59-g8ed1b From 273171bd098028d12ee8d1209bb72a090bb66f2e Mon Sep 17 00:00:00 2001 From: chaviw Date: Wed, 26 Dec 2018 11:46:30 -0800 Subject: Fix drag and drop (1/3) Added ability to send different InputWindowCommands to SurfaceFlinger. Also added transferTouchFocus function from client so it can be translated to an InputWindowCommand and passed to SF. Bug: 120463595 Test: Builds, no uses of new function Change-Id: I17deaf4a96d5a5bf6b14795d66419acffdb10882 --- libs/gui/ISurfaceComposer.cpp | 8 +++++-- libs/gui/LayerState.cpp | 32 ++++++++++++++++++++++++++++ libs/gui/SurfaceComposerClient.cpp | 17 +++++++++++++-- libs/gui/include/gui/ISurfaceComposer.h | 4 +++- libs/gui/include/gui/LayerState.h | 14 ++++++++++++ libs/gui/include/gui/SurfaceComposerClient.h | 2 ++ libs/gui/tests/Surface_test.cpp | 3 ++- services/surfaceflinger/SurfaceFlinger.cpp | 24 ++++++++++++++++----- services/surfaceflinger/SurfaceFlinger.h | 10 ++++++--- 9 files changed, 100 insertions(+), 14 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 799151ae87..2f6ef79af9 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -75,7 +75,8 @@ public: virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, - const sp& applyToken) { + const sp& applyToken, + const InputWindowCommands& commands) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -91,6 +92,7 @@ public: data.writeUint32(flags); data.writeStrongBinder(applyToken); + commands.write(data); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -750,7 +752,9 @@ status_t BnSurfaceComposer::onTransact( uint32_t stateFlags = data.readUint32(); sp applyToken = data.readStrongBinder(); - setTransactionState(state, displays, stateFlags, applyToken); + InputWindowCommands inputWindowCommands; + inputWindowCommands.read(data); + setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands); return NO_ERROR; } case BOOT_FINISHED: { diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 35ce6e393a..e5170ab73b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -379,4 +379,36 @@ void layer_state_t::merge(const layer_state_t& other) { } } +// ------------------------------- InputWindowCommands ---------------------------------------- + +void InputWindowCommands::merge(const InputWindowCommands& other) { + transferTouchFocusCommands + .insert(transferTouchFocusCommands.end(), + std::make_move_iterator(other.transferTouchFocusCommands.begin()), + std::make_move_iterator(other.transferTouchFocusCommands.end())); +} + +void InputWindowCommands::clear() { + transferTouchFocusCommands.clear(); +} + +void InputWindowCommands::write(Parcel& output) const { + output.writeUint32(static_cast(transferTouchFocusCommands.size())); + for (const auto& transferTouchFocusCommand : transferTouchFocusCommands) { + output.writeStrongBinder(transferTouchFocusCommand.fromToken); + output.writeStrongBinder(transferTouchFocusCommand.toToken); + } +} + +void InputWindowCommands::read(const Parcel& input) { + size_t count = input.readUint32(); + transferTouchFocusCommands.clear(); + for (size_t i = 0; i < count; i++) { + TransferTouchFocusCommand transferTouchFocusCommand; + transferTouchFocusCommand.fromToken = input.readStrongBinder(); + transferTouchFocusCommand.toToken = input.readStrongBinder(); + transferTouchFocusCommands.emplace_back(transferTouchFocusCommand); + } +} + }; // namespace android diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 5b004e2805..e043762653 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -166,6 +166,7 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : mEarlyWakeup(other.mEarlyWakeup) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; + mInputWindowCommands = other.mInputWindowCommands; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { @@ -199,6 +200,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr } other.mListenerCallbacks.clear(); + mInputWindowCommands.merge(other.mInputWindowCommands); + return *this; } @@ -265,8 +268,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { mEarlyWakeup = false; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - - sf->setTransactionState(composerStates, displayStates, flags, applyToken); + sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands); + mInputWindowCommands.clear(); mStatus = NO_ERROR; return NO_ERROR; } @@ -804,6 +807,16 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInput s->what |= layer_state_t::eInputInfoChanged; return *this; } + +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::transferTouchFocus( + const sp& fromToken, const sp& toToken) { + InputWindowCommands::TransferTouchFocusCommand transferTouchFocusCommand; + transferTouchFocusCommand.fromToken = fromToken; + transferTouchFocusCommand.toToken = toToken; + mInputWindowCommands.transferTouchFocusCommands.emplace_back(transferTouchFocusCommand); + return *this; +} + #endif SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::destroySurface( diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 8cb40e78ad..e0ff410873 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -42,6 +42,7 @@ struct ComposerState; struct DisplayState; struct DisplayInfo; struct DisplayStatInfo; +struct InputWindowCommands; class LayerDebugInfo; class HdrCapabilities; class IDisplayEventConnection; @@ -125,7 +126,8 @@ public: /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, - const sp& applyToken) = 0; + const sp& applyToken, + const InputWindowCommands& inputWindowCommands) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 02c6be25c7..e7564f5ed4 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -228,6 +228,20 @@ struct DisplayState { status_t read(const Parcel& input); }; +struct InputWindowCommands { + struct TransferTouchFocusCommand { + sp fromToken; + sp toToken; + }; + + std::vector transferTouchFocusCommands; + + void merge(const InputWindowCommands& other); + void clear(); + void write(Parcel& output) const; + void read(const Parcel& input); +}; + static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) { if (lhs.client < rhs.client) return -1; if (lhs.client > rhs.client) return 1; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 8e3ba78108..9765cdd714 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -219,6 +219,7 @@ public: bool mAnimation = false; bool mEarlyWakeup = false; + InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; layer_state_t* getLayerState(const sp& sc); @@ -335,6 +336,7 @@ public: #ifndef NO_INPUT Transaction& setInputWindowInfo(const sp& sc, const InputWindowInfo& info); + Transaction& transferTouchFocus(const sp& fromToken, const sp& toToken); #endif Transaction& destroySurface(const sp& sc); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index c56304fdd4..13fac7fa04 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -559,7 +559,8 @@ public: sp getBuiltInDisplay(int32_t /*id*/) override { return nullptr; } void setTransactionState(const Vector& /*state*/, const Vector& /*displays*/, uint32_t /*flags*/, - const sp& /*applyToken*/) override {} + const sp& /*applyToken*/, + const InputWindowCommands& /*inputWindowCommands*/) override {} void bootFinished() override {} bool authenticateSurfaceTexture( const sp& /*surface*/) const override { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 02cd9d9f61..4d685590cb 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3337,7 +3337,7 @@ bool SurfaceFlinger::flushTransactionQueues() { if (composerStateContainsUnsignaledFences(states)) { break; } - applyTransactionState(states, displays, flags); + applyTransactionState(states, displays, flags, mInputWindowCommands); transactionQueue.pop(); } @@ -3383,7 +3383,8 @@ bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector& states, const Vector& displays, uint32_t flags, - const sp& applyToken) { + const sp& applyToken, + const InputWindowCommands& inputWindowCommands) { ATRACE_CALL(); Mutex::Autolock _l(mStateLock); @@ -3399,11 +3400,12 @@ void SurfaceFlinger::setTransactionState(const Vector& states, return; } - applyTransactionState(states, displays, flags); + applyTransactionState(states, displays, flags, inputWindowCommands); } void SurfaceFlinger::applyTransactionState(const Vector& states, - const Vector& displays, uint32_t flags) { + const Vector& displays, uint32_t flags, + const InputWindowCommands& inputWindowCommands) { uint32_t transactionFlags = 0; if (flags & eAnimation) { @@ -3444,6 +3446,8 @@ void SurfaceFlinger::applyTransactionState(const Vector& states, setDestroyStateLocked(state); } + transactionFlags |= addInputWindowCommands(inputWindowCommands); + // If a synchronous transaction is explicitly requested without any changes, force a transaction // anyway. This can be used as a flush mechanism for previous async transactions. // Empty animation transaction can be used to simulate back-pressure, so also force a @@ -3781,6 +3785,16 @@ void SurfaceFlinger::setDestroyStateLocked(const ComposerState& composerState) { } } +uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) { + uint32_t flags = 0; + if (!inputWindowCommands.transferTouchFocusCommands.empty()) { + flags |= eTraversalNeeded; + } + + mInputWindowCommands.merge(inputWindowCommands); + return flags; +} + status_t SurfaceFlinger::createLayer( const String8& name, const sp& client, @@ -3995,7 +4009,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(state, displays, 0, nullptr); + setTransactionState(state, displays, 0, nullptr, mInputWindowCommands); const auto display = getDisplayDevice(displayToken); if (!display) return; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 822bb18f99..c37f159f7b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -443,7 +443,8 @@ private: virtual sp getBuiltInDisplay(int32_t id); virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, - const sp& applyToken); + const sp& applyToken, + const InputWindowCommands& inputWindowCommands); virtual void bootFinished(); virtual bool authenticateSurfaceTexture( const sp& bufferProducer) const; @@ -555,8 +556,8 @@ private: * Transactions */ void applyTransactionState(const Vector& state, - const Vector& displays, uint32_t flags) - REQUIRES(mStateLock); + const Vector& displays, uint32_t flags, + const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); bool flushTransactionQueues(); uint32_t getTransactionFlags(uint32_t flags); uint32_t peekTransactionFlags(); @@ -570,6 +571,7 @@ private: uint32_t setClientStateLocked(const ComposerState& composerState); uint32_t setDisplayStateLocked(const DisplayState& s); void setDestroyStateLocked(const ComposerState& composerState); + uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands); /* ------------------------------------------------------------------------ * Layer management @@ -1020,6 +1022,8 @@ private: sp mSfConnectionHandle; sp mInputFlinger; + + InputWindowCommands mInputWindowCommands; }; }; // namespace android -- cgit v1.2.3-59-g8ed1b From b89ea9d9533864bc6f73a24a4d33d3edba6d1365 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 10 Dec 2018 13:01:14 -0800 Subject: SurfaceFlinger: Removed createScopedConnection. Scoped connections existed to constrain clients to only making surfaces with parents. However now that we support off-screen parents this is no longer required and we can use normal connections everywhere. We take however care that only priviledged clients can place layers in the current state. Test: Manual Bug: 62536731 Bug: 111373437 Bug: 111297488 Change-Id: I0a034767e92becec63071d7b1e3e71b95d505b77 --- libs/gui/ISurfaceComposer.cpp | 18 ------- libs/gui/SurfaceComposerClient.cpp | 9 +--- libs/gui/SurfaceControl.cpp | 7 +++ libs/gui/include/gui/ISurfaceComposer.h | 16 +----- libs/gui/include/gui/SurfaceComposerClient.h | 2 - libs/gui/include/gui/SurfaceControl.h | 2 + libs/gui/tests/Surface_test.cpp | 4 -- services/surfaceflinger/Client.cpp | 63 +--------------------- services/surfaceflinger/Client.h | 9 ---- services/surfaceflinger/Layer.cpp | 12 ----- services/surfaceflinger/SurfaceFlinger.cpp | 31 ++++------- services/surfaceflinger/SurfaceFlinger.h | 4 +- services/surfaceflinger/tests/Credentials_test.cpp | 20 +------ 13 files changed, 27 insertions(+), 170 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 2f6ef79af9..a481e81131 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -63,16 +63,6 @@ public: return interface_cast(reply.readStrongBinder()); } - virtual sp createScopedConnection( - const sp& parent) - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(IInterface::asBinder(parent)); - remote()->transact(BnSurfaceComposer::CREATE_SCOPED_CONNECTION, data, &reply); - return interface_cast(reply.readStrongBinder()); - } - virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, @@ -711,14 +701,6 @@ status_t BnSurfaceComposer::onTransact( reply->writeStrongBinder(b); return NO_ERROR; } - case CREATE_SCOPED_CONNECTION: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp bufferProducer = - interface_cast(data.readStrongBinder()); - sp b = IInterface::asBinder(createScopedConnection(bufferProducer)); - reply->writeStrongBinder(b); - return NO_ERROR; - } case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e043762653..824e43fb07 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -910,11 +910,6 @@ SurfaceComposerClient::SurfaceComposerClient() { } -SurfaceComposerClient::SurfaceComposerClient(const sp& root) - : mStatus(NO_INIT), mParent(root) -{ -} - SurfaceComposerClient::SurfaceComposerClient(const sp& client) : mStatus(NO_ERROR), mClient(client) { @@ -923,10 +918,8 @@ SurfaceComposerClient::SurfaceComposerClient(const sp& c void SurfaceComposerClient::onFirstRef() { sp sf(ComposerService::getComposerService()); if (sf != nullptr && mStatus == NO_INIT) { - auto rootProducer = mParent.promote(); sp conn; - conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) : - sf->createConnection(); + conn = sf->createConnection(); if (conn != nullptr) { mClient = conn; mStatus = NO_ERROR; diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 3a6dfdada5..b6ef286fd4 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -54,6 +54,13 @@ SurfaceControl::SurfaceControl( { } +SurfaceControl::SurfaceControl(const sp& other) { + mClient = other->mClient; + mHandle = other->mHandle; + mGraphicBufferProducer = other->mGraphicBufferProducer; + mOwned = false; +} + SurfaceControl::~SurfaceControl() { destroy(); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index e0ff410873..1534fca790 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -87,22 +87,11 @@ public: eVsyncSourceSurfaceFlinger = 1 }; - /* create connection with surface flinger, requires - * ACCESS_SURFACE_FLINGER permission + /* + * Create a connection with SurfaceFlinger. */ virtual sp createConnection() = 0; - /** create a scoped connection with surface flinger. - * Surfaces produced with this connection will act - * as children of the passed in GBP. That is to say - * SurfaceFlinger will draw them relative and confined to - * drawing of buffers from the layer associated with parent. - * As this is graphically equivalent in reach to just drawing - * pixels into the parent buffers, it requires no special permission. - */ - virtual sp createScopedConnection( - const sp& parent) = 0; - /* return an IDisplayEventConnection */ virtual sp createDisplayEventConnection( VsyncSource vsyncSource = eVsyncSourceApp) = 0; @@ -356,7 +345,6 @@ public: ENABLE_VSYNC_INJECTIONS, INJECT_VSYNC, GET_LAYER_DEBUG_INFO, - CREATE_SCOPED_CONNECTION, GET_COMPOSITION_PREFERENCE, GET_COLOR_MANAGEMENT, GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 9765cdd714..4a8e01bec1 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -90,7 +90,6 @@ class SurfaceComposerClient : public RefBase public: SurfaceComposerClient(); SurfaceComposerClient(const sp& client); - SurfaceComposerClient(const sp& parent); virtual ~SurfaceComposerClient(); // Always make sure we could initialize @@ -402,7 +401,6 @@ private: mutable Mutex mLock; status_t mStatus; sp mClient; - wp mParent; }; // --------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index ccb30fa8e7..9bba76674d 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -75,6 +75,8 @@ public: status_t getLayerFrameStats(FrameStats* outStats) const; sp getClient() const; + + explicit SurfaceControl(const sp& other); private: // can't be copied diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 13fac7fa04..afc30d17b0 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -545,10 +545,6 @@ public: } sp createConnection() override { return nullptr; } - sp createScopedConnection( - const sp& /* parent */) override { - return nullptr; - } sp createDisplayEventConnection(ISurfaceComposer::VsyncSource) override { return nullptr; diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 0b59147c5a..ee4ec506f7 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -35,13 +35,7 @@ const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER" // --------------------------------------------------------------------------- Client::Client(const sp& flinger) - : Client(flinger, nullptr) -{ -} - -Client::Client(const sp& flinger, const sp& parentLayer) - : mFlinger(flinger), - mParentLayer(parentLayer) + : mFlinger(flinger) { } @@ -65,25 +59,6 @@ Client::~Client() } } -void Client::updateParent(const sp& parentLayer) { - Mutex::Autolock _l(mLock); - - // If we didn't ever have a parent, then we must instead be - // relying on permissions and we never need a parent. - if (mParentLayer != nullptr) { - mParentLayer = parentLayer; - } -} - -sp Client::getParentLayer(bool* outParentDied) const { - Mutex::Autolock _l(mLock); - sp parent = mParentLayer.promote(); - if (outParentDied != nullptr) { - *outParentDied = (mParentLayer != nullptr && parent == nullptr); - } - return parent; -} - status_t Client::initCheck() const { return NO_ERROR; } @@ -119,32 +94,6 @@ sp Client::getLayerUser(const sp& handle) const } -status_t Client::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - // these must be checked - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - const int self_pid = getpid(); - // If we are called from another non root process without the GRAPHICS, SYSTEM, or ROOT - // uid we require the sAccessSurfaceFlinger permission. - // We grant an exception in the case that the Client has a "parent layer", as its - // effects will be scoped to that layer. - if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0) - && (getParentLayer() == nullptr)) { - // we're called from a different process, do the real check - if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) - { - ALOGE("Permission Denial: " - "can't openGlobalTransaction pid=%d, uid<=%d", pid, uid); - return PERMISSION_DENIED; - } - } - return BnSurfaceComposerClient::onTransact(code, data, reply, flags); -} - - status_t Client::createSurface( const String8& name, uint32_t w, uint32_t h, PixelFormat format, uint32_t flags, @@ -160,16 +109,8 @@ status_t Client::createSurface( return NAME_NOT_FOUND; } } - if (parent == nullptr) { - bool parentDied; - parent = getParentLayer(&parentDied); - // If we had a parent, but it died, we've lost all - // our capabilities. - if (parentDied) { - return NAME_NOT_FOUND; - } - } + // We rely on createLayer to check permissions. return mFlinger->createLayer(name, this, w, h, format, flags, windowType, ownerUid, handle, gbp, &parent); } diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h index 49437ed7fd..4a74739a10 100644 --- a/services/surfaceflinger/Client.h +++ b/services/surfaceflinger/Client.h @@ -39,7 +39,6 @@ class Client : public BnSurfaceComposerClient { public: explicit Client(const sp& flinger); - Client(const sp& flinger, const sp& parentLayer); ~Client(); status_t initCheck() const; @@ -51,8 +50,6 @@ public: sp getLayerUser(const sp& handle) const; - void updateParent(const sp& parentLayer); - private: // ISurfaceComposerClient interface virtual status_t createSurface( @@ -68,17 +65,11 @@ private: virtual status_t getLayerFrameStats(const sp& handle, FrameStats* outStats) const; - virtual status_t onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); - - sp getParentLayer(bool* outParentDied = nullptr) const; - // constant sp mFlinger; // protected by mLock DefaultKeyedVector< wp, wp > mLayers; - wp mParentLayer; // thread-safe mutable Mutex mLock; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index f4b3cddc63..2d3fd8ecbb 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -1666,11 +1666,6 @@ bool Layer::reparentChildren(const sp& newParentHandle) { } for (const sp& child : mCurrentChildren) { newParent->addChild(child); - - sp client(child->mClientRef.promote()); - if (client != nullptr) { - client->updateParent(newParent); - } } mCurrentChildren.clear(); @@ -1705,13 +1700,6 @@ bool Layer::reparent(const sp& newParentHandle) { addToCurrentState(); } - sp client(mClientRef.promote()); - sp newParentClient(newParent->mClientRef.promote()); - - if (client != newParentClient) { - client->updateParent(newParent); - } - Mutex::Autolock lock(mStateMutex); if (mLayerDetached) { mLayerDetached = false; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4d685590cb..13997bea21 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -458,19 +458,6 @@ sp SurfaceFlinger::createConnection() { return initClient(new Client(this)); } -sp SurfaceFlinger::createScopedConnection( - const sp& gbp) { - if (authenticateSurfaceTexture(gbp) == false) { - return nullptr; - } - const auto& layer = (static_cast(gbp.get()))->getLayer(); - if (layer == nullptr) { - return nullptr; - } - - return initClient(new Client(this, layer)); -} - sp SurfaceFlinger::createDisplay(const String8& displayName, bool secure) { @@ -3243,7 +3230,8 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, const sp& handle, const sp& gbc, const sp& lbc, - const sp& parent) + const sp& parent, + bool addToCurrentState) { // add this layer to the current state list { @@ -3253,13 +3241,12 @@ status_t SurfaceFlinger::addClientLayer(const sp& client, MAX_LAYERS); return NO_MEMORY; } - if (parent == nullptr) { + if (parent == nullptr && addToCurrentState) { mCurrentState.layersSortedByZ.add(lbc); - } else { - if (parent->isRemovedFromCurrentState()) { + } else if (parent == nullptr || parent->isRemovedFromCurrentState()) { ALOGE("addClientLayer called with a removed parent"); lbc->onRemovedFromCurrentState(); - } + } else { parent->addChild(lbc); } @@ -3864,7 +3851,9 @@ status_t SurfaceFlinger::createLayer( layer->setInfo(windowType, ownerUid); - result = addClientLayer(client, *handle, *gbp, layer, *parent); + bool addToCurrentState = callingThreadHasUnscopedSurfaceFlingerAccess(); + result = addClientLayer(client, *handle, *gbp, layer, *parent, + addToCurrentState); if (result != NO_ERROR) { return result; } @@ -4828,7 +4817,6 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // access to SF. case BOOT_FINISHED: case CLEAR_ANIMATION_FRAME_STATS: - case CREATE_CONNECTION: case CREATE_DISPLAY: case DESTROY_DISPLAY: case ENABLE_VSYNC_INJECTIONS: @@ -4875,8 +4863,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // Calling setTransactionState is safe, because you need to have been // granted a reference to Client* and Handle* to do anything with it. case SET_TRANSACTION_STATE: - // Creating a scoped connection is safe, as per discussion in ISurfaceComposer.h - case CREATE_SCOPED_CONNECTION: + case CREATE_CONNECTION: case GET_COLOR_MANAGEMENT: case GET_COMPOSITION_PREFERENCE: { return OK; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c37f159f7b..bfc87a02eb 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -437,7 +437,6 @@ private: * ISurfaceComposer interface */ virtual sp createConnection(); - virtual sp createScopedConnection(const sp& gbp); virtual sp createDisplay(const String8& displayName, bool secure); virtual void destroyDisplay(const sp& displayToken); virtual sp getBuiltInDisplay(int32_t id); @@ -620,7 +619,8 @@ private: const sp& handle, const sp& gbc, const sp& lbc, - const sp& parent); + const sp& parent, + bool addToCurrentState); /* ------------------------------------------------------------------------ * Boot animation, on/off animations and screen capture diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index a73ec6c7ef..8560f5ed3e 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -162,10 +162,10 @@ TEST_F(CredentialsTest, ClientInitTest) { setSystemUID(); ASSERT_NO_FATAL_FAILURE(initClient()); - // No one else can init the client. + // Anyone else can init the client. setBinUID(); mComposerClient = new SurfaceComposerClient; - ASSERT_EQ(NO_INIT, mComposerClient->initCheck()); + ASSERT_NO_FATAL_FAILURE(initClient()); } TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) { @@ -222,22 +222,6 @@ TEST_F(CredentialsTest, SetActiveColorModeTest) { ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, PERMISSION_DENIED)); } -TEST_F(CredentialsTest, CreateSurfaceTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); - const ssize_t displayWidth = info.w; - const ssize_t displayHeight = info.h; - - std::function condition = [=]() { - mBGSurfaceControl = - mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight, - PIXEL_FORMAT_RGBA_8888, 0); - return mBGSurfaceControl != nullptr && mBGSurfaceControl->isValid(); - }; - ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false)); -} - TEST_F(CredentialsTest, CreateDisplayTest) { std::function condition = [=]() { sp testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true); -- cgit v1.2.3-59-g8ed1b From 3c2791e877992d4782418e502305b570272737f2 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 14 Jan 2019 17:05:18 -0800 Subject: [ComposerService] Add API to query protected content support. Add API to query protected content support for upper stack usage. BUG: 117436546 Test: Build, flash and boot. Check returned value. Change-Id: I1bc7320a2ce5a99889c979f6d6fd159369668871 --- libs/gui/ISurfaceComposer.cpp | 25 +++++++++++++++++++++++-- libs/gui/include/gui/ISurfaceComposer.h | 7 +++++++ libs/gui/tests/Surface_test.cpp | 3 ++- services/surfaceflinger/SurfaceFlinger.cpp | 11 ++++++++++- services/surfaceflinger/SurfaceFlinger.h | 1 + 5 files changed, 43 insertions(+), 4 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a481e81131..7357ba99f4 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -681,6 +681,18 @@ public: result = reply.readUint64Vector(&outStats->component_3_sample); return result; } + + virtual status_t getProtectedContentSupport(bool* outSupported) const { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply); + bool result; + status_t err = reply.readBool(&result); + if (err == NO_ERROR) { + *outSupported = result; + } + return err; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1017,7 +1029,7 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(static_cast(wideColorGamutDataspace)); reply->writeInt32(static_cast(wideColorGamutPixelFormat)); } - return NO_ERROR; + return error; } case GET_COLOR_MANAGEMENT: { CHECK_INTERFACE(ISurfaceComposer, data, reply); @@ -1026,7 +1038,7 @@ status_t BnSurfaceComposer::onTransact( if (error == NO_ERROR) { reply->writeBool(result); } - return result; + return error; } case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: { CHECK_INTERFACE(ISurfaceComposer, data, reply); @@ -1110,6 +1122,15 @@ status_t BnSurfaceComposer::onTransact( } return result; } + case GET_PROTECTED_CONTENT_SUPPORT: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + bool result; + status_t error = getProtectedContentSupport(&result); + if (error == NO_ERROR) { + reply->writeBool(result); + } + return error; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 1534fca790..9812e1ca6f 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -309,6 +309,12 @@ public: virtual status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) const = 0; + + /* + * Gets whether SurfaceFlinger can support protected content in GPU composition. + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t getProtectedContentSupport(bool* outSupported) const = 0; }; // ---------------------------------------------------------------------------- @@ -350,6 +356,7 @@ public: GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, SET_DISPLAY_CONTENT_SAMPLING_ENABLED, GET_DISPLAYED_CONTENT_SAMPLE, + GET_PROTECTED_CONTENT_SUPPORT, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 60173dce15..2d773f240f 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -655,7 +655,8 @@ public: return NO_ERROR; } - virtual status_t getColorManagement(bool* /*outGetColorManagement*/) const { return NO_ERROR; } + status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; } + status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9eff3c6ef6..72ca3635aa 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1153,6 +1153,14 @@ status_t SurfaceFlinger::getDisplayedContentSample(const sp& displayTok outStats); } +status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const { + if (!outSupported) { + return BAD_VALUE; + } + *outSupported = getRenderEngine().supportsProtectedContent(); + return NO_ERROR; +} + status_t SurfaceFlinger::enableVSyncInjections(bool enable) { postMessageSync(new LambdaMessage([&] { Mutex::Autolock _l(mStateLock); @@ -5004,7 +5012,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case SET_TRANSACTION_STATE: case CREATE_CONNECTION: case GET_COLOR_MANAGEMENT: - case GET_COMPOSITION_PREFERENCE: { + case GET_COMPOSITION_PREFERENCE: + case GET_PROTECTED_CONTENT_SUPPORT: { return OK; } case CAPTURE_LAYERS: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 134f9c2531..460f0412c0 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -457,6 +457,7 @@ private: status_t getDisplayedContentSample(const sp& display, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) const override; + status_t getProtectedContentSupport(bool* outSupported) const override; /* ------------------------------------------------------------------------ * DeathRecipient interface -- cgit v1.2.3-59-g8ed1b From 17b4e4570fed99881a94730b9ad67b590aa426b9 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Wed, 26 Dec 2018 16:32:34 -0800 Subject: blast: add desired present time Add the option to set a desiredPresentTime for a transaction. This lets the framework know approximately when the transaction should be presented. Test: Transaction_test Bug: 80477568 Change-Id: Ic25617fb93f2c249b3b3c7a8f90f72ec358938f0 --- libs/gui/ISurfaceComposer.cpp | 9 +- libs/gui/SurfaceComposerClient.cpp | 22 ++- libs/gui/include/gui/ISurfaceComposer.h | 3 +- libs/gui/include/gui/SurfaceComposerClient.h | 13 ++ libs/gui/tests/Surface_test.cpp | 4 +- services/surfaceflinger/Scheduler/DispSync.cpp | 3 + services/surfaceflinger/SurfaceFlinger.cpp | 28 ++-- services/surfaceflinger/SurfaceFlinger.h | 15 ++- services/surfaceflinger/tests/Transaction_test.cpp | 150 +++++++++++++++++++++ 9 files changed, 223 insertions(+), 24 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 7357ba99f4..c3a4737e0e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -66,7 +66,8 @@ public: virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& commands) { + const InputWindowCommands& commands, + int64_t desiredPresentTime) { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -83,6 +84,7 @@ public: data.writeUint32(flags); data.writeStrongBinder(applyToken); commands.write(data); + data.writeInt64(desiredPresentTime); remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply); } @@ -748,7 +750,10 @@ status_t BnSurfaceComposer::onTransact( sp applyToken = data.readStrongBinder(); InputWindowCommands inputWindowCommands; inputWindowCommands.read(data); - setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands); + + int64_t desiredPresentTime = data.readInt64(); + setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands, + desiredPresentTime); return NO_ERROR; } case BOOT_FINISHED: { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 8b9e4d7fee..32a368ebab 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -159,11 +159,12 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener // --------------------------------------------------------------------------- -SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : - mForceSynchronous(other.mForceSynchronous), - mTransactionNestCount(other.mTransactionNestCount), - mAnimation(other.mAnimation), - mEarlyWakeup(other.mEarlyWakeup) { +SurfaceComposerClient::Transaction::Transaction(const Transaction& other) + : mForceSynchronous(other.mForceSynchronous), + mTransactionNestCount(other.mTransactionNestCount), + mAnimation(other.mAnimation), + mEarlyWakeup(other.mEarlyWakeup), + mDesiredPresentTime(other.mDesiredPresentTime) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; @@ -218,7 +219,7 @@ void SurfaceComposerClient::doDropReferenceTransaction(const sp& handle s.state.parentHandleForChild = nullptr; composerStates.add(s); - sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}); + sf->setTransactionState(composerStates, displayStates, 0, nullptr, {}, -1); } status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { @@ -284,7 +285,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous) { mEarlyWakeup = false; sp applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands); + sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands, + mDesiredPresentTime); mInputWindowCommands.clear(); mStatus = NO_ERROR; return NO_ERROR; @@ -742,6 +744,12 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSideb return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime( + nsecs_t desiredPresentTime) { + mDesiredPresentTime = desiredPresentTime; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCompletedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext) { diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 9812e1ca6f..25a4185dec 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -116,7 +116,8 @@ public: virtual void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& inputWindowCommands) = 0; + const InputWindowCommands& inputWindowCommands, + int64_t desiredPresentTime) = 0; /* signal that we're done booting. * Requires ACCESS_SURFACE_FLINGER permission diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f16f7814e2..2f02328c99 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -237,6 +237,18 @@ public: bool mAnimation = false; bool mEarlyWakeup = false; + // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction + // to be presented. When it is not possible to present at exactly that time, it will be + // presented after the time has passed. + // + // Desired present times that are more than 1 second in the future may be ignored. + // When a desired present time has already passed, the transaction will be presented as soon + // as possible. + // + // Transactions from the same process are presented in the same order that they are applied. + // The desired present time does not affect this ordering. + int64_t mDesiredPresentTime = -1; + InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; @@ -325,6 +337,7 @@ public: Transaction& setApi(const sp& sc, int32_t api); Transaction& setSidebandStream(const sp& sc, const sp& sidebandStream); + Transaction& setDesiredPresentTime(nsecs_t desiredPresentTime); Transaction& addTransactionCompletedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 2d773f240f..1d2950af19 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -556,7 +556,9 @@ public: void setTransactionState(const Vector& /*state*/, const Vector& /*displays*/, uint32_t /*flags*/, const sp& /*applyToken*/, - const InputWindowCommands& /*inputWindowCommands*/) override {} + const InputWindowCommands& /*inputWindowCommands*/, + int64_t /*desiredPresentTime*/) override {} + void bootFinished() override {} bool authenticateSurfaceTexture( const sp& /*surface*/) const override { diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index b74b9010d2..9b2a6fc096 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -657,6 +657,9 @@ nsecs_t DispSync::computeNextRefresh(int periodOffset) const { Mutex::Autolock lock(mMutex); nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); nsecs_t phase = mReferenceTime + mPhase; + if (mPeriod == 0) { + return 0; + } return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dc02666559..c0059d5e2e 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -3498,8 +3498,8 @@ bool SurfaceFlinger::flushTransactionQueues() { auto& [applyToken, transactionQueue] = *it; while (!transactionQueue.empty()) { - const auto& [states, displays, flags] = transactionQueue.front(); - if (composerStateContainsUnsignaledFences(states)) { + const auto& [states, displays, flags, desiredPresentTime] = transactionQueue.front(); + if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) { break; } applyTransactionState(states, displays, flags, mInputWindowCommands); @@ -3533,23 +3533,33 @@ bool SurfaceFlinger::containsAnyInvalidClientState(const Vector& return false; } -bool SurfaceFlinger::composerStateContainsUnsignaledFences(const Vector& states) { +bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime, + const Vector& states) { + const nsecs_t expectedPresentTime = mPrimaryDispSync->expectedPresentTime(); + // Do not present if the desiredPresentTime has not passed unless it is more than one second + // in the future. We ignore timestamps more than 1 second in the future for stability reasons. + if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime && + desiredPresentTime < expectedPresentTime + s2ns(1)) { + return false; + } + for (const ComposerState& state : states) { const layer_state_t& s = state.state; if (!(s.what & layer_state_t::eAcquireFenceChanged)) { continue; } if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) { - return true; + return false; } } - return false; + return true; } void SurfaceFlinger::setTransactionState(const Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& inputWindowCommands) { + const InputWindowCommands& inputWindowCommands, + int64_t desiredPresentTime) { ATRACE_CALL(); Mutex::Autolock _l(mStateLock); @@ -3559,8 +3569,8 @@ void SurfaceFlinger::setTransactionState(const Vector& states, // If its TransactionQueue already has a pending TransactionState or if it is pending if (mTransactionQueues.find(applyToken) != mTransactionQueues.end() || - composerStateContainsUnsignaledFences(states)) { - mTransactionQueues[applyToken].emplace(states, displays, flags); + !transactionIsReadyToBeApplied(desiredPresentTime, states)) { + mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime); setTransactionFlags(eTransactionNeeded); return; } @@ -4147,7 +4157,7 @@ void SurfaceFlinger::onInitializeDisplays() { d.width = 0; d.height = 0; displays.add(d); - setTransactionState(state, displays, 0, nullptr, mInputWindowCommands); + setTransactionState(state, displays, 0, nullptr, mInputWindowCommands, -1); const auto display = getDisplayDevice(displayToken); if (!display) return; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c92874bab4..e5b3570fe3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -412,7 +412,8 @@ private: void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, - const InputWindowCommands& inputWindowCommands) override; + const InputWindowCommands& inputWindowCommands, + int64_t desiredPresentTime) override; void bootFinished() override; bool authenticateSurfaceTexture( const sp& bufferProducer) const override; @@ -537,7 +538,8 @@ private: void latchAndReleaseBuffer(const sp& layer); void commitTransaction(); bool containsAnyInvalidClientState(const Vector& states); - bool composerStateContainsUnsignaledFences(const Vector& states); + bool transactionIsReadyToBeApplied(int64_t desiredPresentTime, + const Vector& states); uint32_t setClientStateLocked(const ComposerState& composerState); uint32_t setDisplayStateLocked(const DisplayState& s); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands); @@ -982,12 +984,17 @@ private: }; struct TransactionState { TransactionState(const Vector& composerStates, - const Vector& displayStates, uint32_t transactionFlags) - : states(composerStates), displays(displayStates), flags(transactionFlags) {} + const Vector& displayStates, uint32_t transactionFlags, + int64_t desiredPresentTime) + : states(composerStates), + displays(displayStates), + flags(transactionFlags), + time(desiredPresentTime) {} Vector states; Vector displays; uint32_t flags; + int64_t time; }; std::unordered_map, std::queue, IBinderHash> mTransactionQueues; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 9339761837..0ad2711fc9 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -2568,11 +2568,23 @@ public: } } + void addExpectedPresentTime(nsecs_t expectedPresentTime) { + mExpectedPresentTime = expectedPresentTime; + } + void verifyTransactionStats(const TransactionStats& transactionStats) const { const auto& [latchTime, presentFence, surfaceStats] = transactionStats; if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) { ASSERT_GE(latchTime, 0) << "bad latch time"; ASSERT_NE(presentFence, nullptr); + if (mExpectedPresentTime >= 0) { + ASSERT_EQ(presentFence->wait(3000), NO_ERROR); + ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6)); + // if the panel is running at 30 hz, at the worst case, our expected time just + // misses vsync and we have to wait another 33.3ms + ASSERT_LE(presentFence->getSignalTime(), + mExpectedPresentTime + nsecs_t(66.666666 * 1e6)); + } } else { ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented"; ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched"; @@ -2623,6 +2635,7 @@ private: } }; ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED; + nsecs_t mExpectedPresentTime = -1; std::unordered_map, ExpectedSurfaceResult, IBinderHash> mExpectedSurfaceResults; }; @@ -3272,6 +3285,143 @@ TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) { EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true)); } +TEST_F(LayerCallbackTest, DesiredPresentTime) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + + Transaction transaction; + CallbackHelper callback; + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + // Try to present 100ms in the future + nsecs_t time = systemTime() + (100 * 1e6); + + transaction.setDesiredPresentTime(time); + transaction.apply(); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + expected.addExpectedPresentTime(time); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); +} + +TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + + Transaction transaction; + CallbackHelper callback1; + int err = fillTransaction(transaction, &callback1, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + // Try to present 100ms in the future + nsecs_t time = systemTime() + (100 * 1e6); + + transaction.setDesiredPresentTime(time); + transaction.apply(); + + ExpectedResult expected1; + expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + expected1.addExpectedPresentTime(time); + + CallbackHelper callback2; + err = fillTransaction(transaction, &callback2, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + // Try to present 33ms after the first frame + time += (33.3 * 1e6); + + transaction.setDesiredPresentTime(time); + transaction.apply(); + + ExpectedResult expected2; + expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::ACQUIRED, + ExpectedResult::PreviousBuffer::RELEASED); + expected2.addExpectedPresentTime(time); + + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true)); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true)); +} + +TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + + Transaction transaction; + CallbackHelper callback1; + int err = fillTransaction(transaction, &callback1, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + // Try to present 100ms in the future + nsecs_t time = systemTime() + (100 * 1e6); + + transaction.setDesiredPresentTime(time); + transaction.apply(); + + ExpectedResult expected1; + expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + expected1.addExpectedPresentTime(time); + + CallbackHelper callback2; + err = fillTransaction(transaction, &callback2, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + // Try to present 33ms before the previous frame + time -= (33.3 * 1e6); + + transaction.setDesiredPresentTime(time); + transaction.apply(); + + ExpectedResult expected2; + expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer, + ExpectedResult::Buffer::ACQUIRED, + ExpectedResult::PreviousBuffer::RELEASED); + + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true)); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true)); +} + +TEST_F(LayerCallbackTest, DesiredPresentTime_Past) { + sp layer; + ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer()); + + Transaction transaction; + CallbackHelper callback; + int err = fillTransaction(transaction, &callback, layer); + if (err) { + GTEST_SUCCEED() << "test not supported"; + return; + } + + // Try to present 100ms in the past + nsecs_t time = systemTime() - (100 * 1e6); + + transaction.setDesiredPresentTime(time); + transaction.apply(); + + ExpectedResult expected; + expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer); + expected.addExpectedPresentTime(systemTime()); + EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true)); +} + class LayerUpdateTest : public LayerTransactionTest { protected: virtual void SetUp() { -- cgit v1.2.3-59-g8ed1b From ebc2c059e73d3278e07c461b3f4e844a47019c3d Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Wed, 16 Jan 2019 19:16:55 -0800 Subject: blast: cache buffers Cache incoming buffers so they don't have to be imported by mapper everytime they are set. Amended by Change-Id: I3040f6d8886ca9b130115784c199edfdd9c85c7e Test: Transaction_test Bug: 80477568 Change-Id: Icd167c5e5bd59d7331b829667b1139919393d98b --- libs/gui/ISurfaceComposer.cpp | 78 ++++++++++++ libs/gui/LayerState.cpp | 10 ++ libs/gui/SurfaceComposerClient.cpp | 35 ++++++ libs/gui/include/gui/ISurfaceComposer.h | 7 ++ libs/gui/include/gui/LayerState.h | 7 ++ libs/gui/include/gui/SurfaceComposerClient.h | 7 ++ libs/gui/tests/Surface_test.cpp | 6 + services/surfaceflinger/Android.bp | 1 + services/surfaceflinger/BufferStateLayerCache.cpp | 99 +++++++++++++++ services/surfaceflinger/BufferStateLayerCache.h | 55 +++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 23 +++- services/surfaceflinger/SurfaceFlinger.h | 6 + services/surfaceflinger/tests/Transaction_test.cpp | 137 +++++++++++++++++++++ 13 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 services/surfaceflinger/BufferStateLayerCache.cpp create mode 100644 services/surfaceflinger/BufferStateLayerCache.h (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index c3a4737e0e..ad2dc14858 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -695,6 +695,42 @@ public: } return err; } + + virtual status_t cacheBuffer(const sp& token, const sp& buffer, + int32_t* outBufferId) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + + data.writeStrongBinder(token); + if (buffer) { + data.writeBool(true); + data.write(*buffer); + } else { + data.writeBool(false); + } + + status_t result = remote()->transact(BnSurfaceComposer::CACHE_BUFFER, data, &reply); + if (result != NO_ERROR) { + return result; + } + + int32_t id = -1; + result = reply.readInt32(&id); + if (result == NO_ERROR) { + *outBufferId = id; + } + return result; + } + + virtual status_t uncacheBuffer(const sp& token, int32_t bufferId) { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + + data.writeStrongBinder(token); + data.writeInt32(bufferId); + + return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1136,6 +1172,48 @@ status_t BnSurfaceComposer::onTransact( } return error; } + case CACHE_BUFFER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp token; + status_t result = data.readStrongBinder(&token); + if (result != NO_ERROR) { + ALOGE("cache buffer failure in reading token: %d", result); + return result; + } + + sp buffer = new GraphicBuffer(); + if (data.readBool()) { + result = data.read(*buffer); + if (result != NO_ERROR) { + ALOGE("cache buffer failure in reading buffer: %d", result); + return result; + } + } + int32_t bufferId = -1; + status_t error = cacheBuffer(token, buffer, &bufferId); + if (error == NO_ERROR) { + reply->writeInt32(bufferId); + } + return error; + } + case UNCACHE_BUFFER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp token; + status_t result = data.readStrongBinder(&token); + if (result != NO_ERROR) { + ALOGE("uncache buffer failure in reading token: %d", result); + return result; + } + + int32_t bufferId = -1; + result = data.readInt32(&bufferId); + if (result != NO_ERROR) { + ALOGE("uncache buffer failure in reading buffer id: %d", result); + return result; + } + + return uncacheBuffer(token, bufferId); + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index e5170ab73b..40b55fa28b 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -94,6 +94,9 @@ status_t layer_state_t::write(Parcel& output) const } } + output.writeStrongBinder(cachedBuffer.token); + output.writeInt32(cachedBuffer.bufferId); + return NO_ERROR; } @@ -164,6 +167,9 @@ status_t layer_state_t::read(const Parcel& input) listenerCallbacks.emplace_back(listener, callbackIds); } + cachedBuffer.token = input.readStrongBinder(); + cachedBuffer.bufferId = input.readInt32(); + return NO_ERROR; } @@ -372,6 +378,10 @@ void layer_state_t::merge(const layer_state_t& other) { } #endif + if (other.what & eCachedBufferChanged) { + what |= eCachedBufferChanged; + cachedBuffer = other.cachedBuffer; + } if ((other.what & what) != other.what) { ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? " "other.what=0x%" PRIu64 " what=0x%" PRIu64, diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 32a368ebab..35659e96a9 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -660,6 +660,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachedBuffer( + const sp& sc, int32_t bufferId) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eCachedBufferChanged; + s->cachedBuffer.token = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + s->cachedBuffer.bufferId = bufferId; + + registerSurfaceControlForCallback(sc); + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAcquireFence( const sp& sc, const sp& fence) { layer_state_t* s = getLayerState(sc); @@ -1057,6 +1072,26 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp& token, // ---------------------------------------------------------------------------- +status_t SurfaceComposerClient::cacheBuffer(const sp& buffer, int32_t* outBufferId) { + sp sf(ComposerService::getComposerService()); + if (buffer == nullptr || outBufferId == nullptr) { + return BAD_VALUE; + } + return sf->cacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()), + buffer, outBufferId); +} + +status_t SurfaceComposerClient::uncacheBuffer(int32_t bufferId) { + sp sf(ComposerService::getComposerService()); + if (bufferId < 0) { + return BAD_VALUE; + } + return sf->uncacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()), + bufferId); +} + +// ---------------------------------------------------------------------------- + status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { sp sf(ComposerService::getComposerService()); return sf->enableVSyncInjections(enable); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 25a4185dec..418d5fbf35 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -316,6 +316,11 @@ public: * Requires the ACCESS_SURFACE_FLINGER permission. */ virtual status_t getProtectedContentSupport(bool* outSupported) const = 0; + + virtual status_t cacheBuffer(const sp& token, const sp& buffer, + int32_t* outBufferId) = 0; + + virtual status_t uncacheBuffer(const sp& token, int32_t bufferId) = 0; }; // ---------------------------------------------------------------------------- @@ -358,6 +363,8 @@ public: SET_DISPLAY_CONTENT_SAMPLING_ENABLED, GET_DISPLAYED_CONTENT_SAMPLE, GET_PROTECTED_CONTENT_SUPPORT, + CACHE_BUFFER, + UNCACHE_BUFFER, }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index e7564f5ed4..af314208de 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -84,6 +84,7 @@ struct layer_state_t { eInputInfoChanged = 0x40000000, eCornerRadiusChanged = 0x80000000, eFrameChanged = 0x1'00000000, + eCachedBufferChanged = 0x2'00000000, }; layer_state_t() @@ -125,6 +126,10 @@ struct layer_state_t { float dtdy{0}; float dsdy{0}; }; + struct cached_buffer_t { + sp token = nullptr; + int32_t bufferId = -1; + }; sp surface; uint64_t what; float x; @@ -173,6 +178,8 @@ struct layer_state_t { #ifndef NO_INPUT InputWindowInfo inputInfo; #endif + + cached_buffer_t cachedBuffer; }; struct ComposerState { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 2f02328c99..78515d0d6c 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -152,6 +152,12 @@ public: static void doDropReferenceTransaction(const sp& handle, const sp& client); + // Caches a buffer with the ISurfaceComposer so the buffer does not need to be resent across + // processes + static status_t cacheBuffer(const sp& buffer, int32_t* outBufferId); + // Uncaches a buffer set by cacheBuffer + static status_t uncacheBuffer(int32_t bufferId); + // ------------------------------------------------------------------------ // surface creation / destruction @@ -329,6 +335,7 @@ public: Transaction& setCrop(const sp& sc, const Rect& crop); Transaction& setFrame(const sp& sc, const Rect& frame); Transaction& setBuffer(const sp& sc, const sp& buffer); + Transaction& setCachedBuffer(const sp& sc, int32_t bufferId); Transaction& setAcquireFence(const sp& sc, const sp& fence); Transaction& setDataspace(const sp& sc, ui::Dataspace dataspace); Transaction& setHdrMetadata(const sp& sc, const HdrMetadata& hdrMetadata); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 1d2950af19..259ef9f212 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -660,6 +660,12 @@ public: status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; } status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; } + status_t cacheBuffer(const sp& /*token*/, const sp& /*buffer*/, + int32_t* /*outBufferId*/) { + return NO_ERROR; + } + status_t uncacheBuffer(const sp& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 5b3bbca49f..033ed668c0 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -114,6 +114,7 @@ filegroup { "BufferLayerConsumer.cpp", "BufferQueueLayer.cpp", "BufferStateLayer.cpp", + "BufferStateLayerCache.cpp", "Client.cpp", "ColorLayer.cpp", "ContainerLayer.cpp", diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp new file mode 100644 index 0000000000..c82ad7bc49 --- /dev/null +++ b/services/surfaceflinger/BufferStateLayerCache.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "BufferStateLayerCache" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "BufferStateLayerCache.h" + +#define MAX_CACHE_SIZE 64 + +namespace android { + +int32_t BufferStateLayerCache::add(const sp& processToken, + const sp& buffer) { + std::lock_guard lock(mMutex); + + auto& processCache = getProccessCache(processToken); + + int32_t slot = findSlot(processCache); + if (slot < 0) { + return slot; + } + + processCache[slot] = buffer; + + return slot; +} + +void BufferStateLayerCache::release(const sp& processToken, int32_t id) { + if (id < 0) { + ALOGE("invalid buffer id"); + return; + } + + std::lock_guard lock(mMutex); + auto& processCache = getProccessCache(processToken); + + if (id >= processCache.size()) { + ALOGE("invalid buffer id"); + return; + } + processCache[id] = nullptr; +} + +sp BufferStateLayerCache::get(const sp& processToken, int32_t id) { + if (id < 0) { + ALOGE("invalid buffer id"); + return nullptr; + } + + std::lock_guard lock(mMutex); + auto& processCache = getProccessCache(processToken); + + if (id >= processCache.size()) { + ALOGE("invalid buffer id"); + return nullptr; + } + return processCache[id]; +} + +std::vector>& BufferStateLayerCache::getProccessCache( + const sp& processToken) { + return mBuffers[processToken]; +} + +int32_t BufferStateLayerCache::findSlot(std::vector>& processCache) { + int32_t slot = 0; + + for (const sp buffer : processCache) { + if (!buffer) { + return slot; + } + slot++; + } + + if (processCache.size() < MAX_CACHE_SIZE) { + processCache.push_back(nullptr); + return slot; + } + + return -1; +} + +}; // namespace android diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h new file mode 100644 index 0000000000..623f0c65fd --- /dev/null +++ b/services/surfaceflinger/BufferStateLayerCache.h @@ -0,0 +1,55 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace android { + +class BufferStateLayerCache { +public: + int32_t add(const sp& processToken, const sp& buffer); + void release(const sp& processToken, int32_t id); + + sp get(const sp& processToken, int32_t id); + +private: + std::mutex mMutex; + + std::vector>& getProccessCache(const sp& processToken) + REQUIRES(mMutex); + + int32_t findSlot(std::vector>& proccessCache) REQUIRES(mMutex); + + struct IBinderHash { + std::size_t operator()(const sp& strongPointer) const { + return std::hash{}(strongPointer.get()); + } + }; + + std::unordered_map /*caching process*/, std::vector>, IBinderHash> + mBuffers GUARDED_BY(mMutex); +}; + +}; // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c0059d5e2e..26406250c3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1160,6 +1160,20 @@ status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const { return NO_ERROR; } +status_t SurfaceFlinger::cacheBuffer(const sp& token, const sp& buffer, + int32_t* outBufferId) { + if (!outBufferId) { + return BAD_VALUE; + } + *outBufferId = mBufferStateLayerCache.add(token, buffer); + return NO_ERROR; +} + +status_t SurfaceFlinger::uncacheBuffer(const sp& token, int32_t bufferId) { + mBufferStateLayerCache.release(token, bufferId); + return NO_ERROR; +} + status_t SurfaceFlinger::enableVSyncInjections(bool enable) { postMessageSync(new LambdaMessage([&] { Mutex::Autolock _l(mStateLock); @@ -3932,6 +3946,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); } } + if (what & layer_state_t::eCachedBufferChanged) { + sp buffer = + mBufferStateLayerCache.get(s.cachedBuffer.token, s.cachedBuffer.bufferId); + if (layer->setBuffer(buffer)) flags |= eTraversalNeeded; + } if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; // Do not put anything that updates layer state or modifies flags after // setTransactionCompletedListener @@ -5025,7 +5044,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CREATE_CONNECTION: case GET_COLOR_MANAGEMENT: case GET_COMPOSITION_PREFERENCE: - case GET_PROTECTED_CONTENT_SUPPORT: { + case GET_PROTECTED_CONTENT_SUPPORT: + case CACHE_BUFFER: + case UNCACHE_BUFFER: { return OK; } case CAPTURE_LAYERS: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e5b3570fe3..1e6db068e3 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -48,6 +48,7 @@ #include #include "Barrier.h" +#include "BufferStateLayerCache.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/HWComposer.h" @@ -459,6 +460,9 @@ private: uint64_t timestamp, DisplayedFrameStats* outStats) const override; status_t getProtectedContentSupport(bool* outSupported) const override; + status_t cacheBuffer(const sp& token, const sp& buffer, + int32_t* outBufferId) override; + status_t uncacheBuffer(const sp& token, int32_t bufferId) override; /* ------------------------------------------------------------------------ * DeathRecipient interface @@ -1034,6 +1038,8 @@ private: sp mInputFlinger; InputWindowCommands mInputWindowCommands; + + BufferStateLayerCache mBufferStateLayerCache; }; }; // namespace android diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 0ad2711fc9..216532a814 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -2323,6 +2323,143 @@ TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) { Transaction().setSidebandStream(layer, nullptr).apply(); } +TEST_F(LayerTransactionTest, CacheBuffer_BufferState) { + sp buffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + + int32_t bufferId = -1; + ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); + ASSERT_GE(bufferId, 0); + + ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); +} + +TEST_F(LayerTransactionTest, CacheBuffers_BufferState) { + std::vector bufferIds; + int32_t bufferCount = 20; + + for (int i = 0; i < bufferCount; i++) { + sp buffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + int32_t bufferId = -1; + ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); + if (bufferId < 0) { + EXPECT_GE(bufferId, 0); + break; + } + bufferIds.push_back(bufferId); + } + + for (int32_t bufferId : bufferIds) { + ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); + } +} + +TEST_F(LayerTransactionTest, CacheBufferInvalid_BufferState) { + sp buffer = nullptr; + + int32_t bufferId = -1; + ASSERT_NE(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); + ASSERT_LT(bufferId, 0); +} + +TEST_F(LayerTransactionTest, UncacheBufferTwice_BufferState) { + sp buffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + + int32_t bufferId = -1; + ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); + ASSERT_GE(bufferId, 0); + + ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); + mClient->uncacheBuffer(bufferId); +} + +TEST_F(LayerTransactionTest, UncacheBufferInvalidId_BufferState) { + mClient->uncacheBuffer(-1); + mClient->uncacheBuffer(0); + mClient->uncacheBuffer(1); + mClient->uncacheBuffer(5); + mClient->uncacheBuffer(1000); +} + +TEST_F(LayerTransactionTest, SetCachedBuffer_BufferState) { + sp layer; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + + sp buffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + + fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); + + int32_t bufferId = -1; + ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); + ASSERT_GE(bufferId, 0); + + Transaction().setCachedBuffer(layer, bufferId).apply(); + + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + + ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); +} + +TEST_F(LayerTransactionTest, SetCachedBufferDelayed_BufferState) { + sp layer; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + + sp cachedBuffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + int32_t bufferId = -1; + ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(cachedBuffer, &bufferId)); + ASSERT_GE(bufferId, 0); + + sp buffer = + new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::BLUE); + Transaction().setBuffer(layer, buffer).apply(); + { + SCOPED_TRACE("Uncached buffer"); + + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } + + fillGraphicBufferColor(cachedBuffer, Rect(0, 0, 32, 32), Color::RED); + Transaction().setCachedBuffer(layer, bufferId).apply(); + { + SCOPED_TRACE("Cached buffer"); + + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), Color::RED); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } + + ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); +} + class ColorTransformHelper { public: static void DegammaColorSingle(half& s) { -- cgit v1.2.3-59-g8ed1b From 4f3fddf272851052db5e08db3a828d911e3e4605 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Thu, 24 Jan 2019 17:21:24 -0800 Subject: Eliminate the usage of ConfigStore in native/libs/gui. Ideally modules above SurfaceFlinger should query ConfigStore through ISurfaceComposer APIs. Previously Surface::getWideColorSupport directly evaluate wide color support for built-in display, we don't want that, we should align it with SurfaceFlinger. This patch essentially creates an API to allow other modules to query whether a given display is a wide color display. As a result, we must enforce that wide color display board config together with the wide color modes returned from hardware composer. BUG: 123312783 Test: Build, flash and boot. Verify in logcat. Test: SurfaceFlinger_test --gtest_filter=CredentialsTest.IsWideColorDisplay\* Change-Id: I0a5e3cc404e5365343adb0c9efaee8c13cc49cfe --- libs/gui/Android.bp | 2 -- libs/gui/ISurfaceComposer.cpp | 35 ++++++++++++++++++++++ libs/gui/Surface.cpp | 34 ++------------------- libs/gui/SurfaceComposerClient.cpp | 6 ++++ libs/gui/include/gui/ISurfaceComposer.h | 9 ++++++ libs/gui/include/gui/SurfaceComposerClient.h | 3 ++ libs/gui/tests/Surface_test.cpp | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 17 ++++++++++- services/surfaceflinger/SurfaceFlinger.h | 2 ++ services/surfaceflinger/tests/Credentials_test.cpp | 33 ++++++++++++++++++++ 10 files changed, 107 insertions(+), 35 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 3521e89ae6..ff88a50cd7 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -141,8 +141,6 @@ cc_library_shared { "libhidltransport", "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", - "android.hardware.configstore@1.0", - "android.hardware.configstore-utils", ], // bufferhub is not used when building libgui for vendors diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index ad2dc14858..a7e51e09a6 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -731,6 +731,26 @@ public: return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply); } + + virtual status_t isWideColorDisplay(const sp& token, + bool* outIsWideColorDisplay) const { + Parcel data, reply; + status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (error != NO_ERROR) { + return error; + } + error = data.writeStrongBinder(token); + if (error != NO_ERROR) { + return error; + } + + error = remote()->transact(BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY, data, &reply); + if (error != NO_ERROR) { + return error; + } + error = reply.readBool(outIsWideColorDisplay); + return error; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1167,6 +1187,7 @@ status_t BnSurfaceComposer::onTransact( CHECK_INTERFACE(ISurfaceComposer, data, reply); bool result; status_t error = getProtectedContentSupport(&result); + reply->writeInt32(error); if (error == NO_ERROR) { reply->writeBool(result); } @@ -1214,6 +1235,20 @@ status_t BnSurfaceComposer::onTransact( return uncacheBuffer(token, bufferId); } + case IS_WIDE_COLOR_DISPLAY: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp display = nullptr; + status_t error = data.readStrongBinder(&display); + if (error != NO_ERROR) { + return error; + } + bool result; + error = isWideColorDisplay(display, &result); + if (error == NO_ERROR) { + reply->writeBool(result); + } + return error; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 00e23f0df1..1f726b2ba4 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -39,9 +39,6 @@ #include #include -#include -#include - namespace android { using ui::ColorMode; @@ -321,41 +318,14 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber, return NO_ERROR; } -using namespace android::hardware::configstore; -using namespace android::hardware::configstore::V1_0; - status_t Surface::getWideColorSupport(bool* supported) { ATRACE_CALL(); sp display( composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - Vector colorModes; - status_t err = - composerService()->getDisplayColorModes(display, &colorModes); - - if (err) - return err; - - bool wideColorBoardConfig = - getBool(false); - *supported = false; - for (ColorMode colorMode : colorModes) { - switch (colorMode) { - case ColorMode::DISPLAY_P3: - case ColorMode::ADOBE_RGB: - case ColorMode::DCI_P3: - if (wideColorBoardConfig) { - *supported = true; - } - break; - default: - break; - } - } - - return NO_ERROR; + status_t error = composerService()->isWideColorDisplay(display, supported); + return error; } status_t Surface::getHdrSupport(bool* supported) { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 6c1c52e1bd..e9632536a0 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1361,6 +1361,12 @@ status_t SurfaceComposerClient::getDisplayedContentSample(const sp& dis timestamp, outStats); } +status_t SurfaceComposerClient::isWideColorDisplay(const sp& display, + bool* outIsWideColorDisplay) { + return ComposerService::getComposerService()->isWideColorDisplay(display, + outIsWideColorDisplay); +} + // ---------------------------------------------------------------------------- status_t ScreenshotClient::capture(const sp& display, const ui::Dataspace reqDataSpace, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 418d5fbf35..bbfc8c45fc 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -321,6 +321,13 @@ public: int32_t* outBufferId) = 0; virtual status_t uncacheBuffer(const sp& token, int32_t bufferId) = 0; + + /* + * Queries whether the given display is a wide color display. + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + virtual status_t isWideColorDisplay(const sp& token, + bool* outIsWideColorDisplay) const = 0; }; // ---------------------------------------------------------------------------- @@ -365,6 +372,8 @@ public: GET_PROTECTED_CONTENT_SUPPORT, CACHE_BUFFER, UNCACHE_BUFFER, + IS_WIDE_COLOR_DISPLAY, + // Always append new enum to the end. }; virtual status_t onTransact(uint32_t code, const Parcel& data, diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 24b656b543..4ba6fc960a 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -153,6 +153,9 @@ public: // Uncaches a buffer set by cacheBuffer static status_t uncacheBuffer(int32_t bufferId); + // Queries whether a given display is wide color display. + static status_t isWideColorDisplay(const sp& display, bool* outIsWideColorDisplay); + // ------------------------------------------------------------------------ // surface creation / destruction diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 259ef9f212..d525a338db 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -665,6 +665,7 @@ public: return NO_ERROR; } status_t uncacheBuffer(const sp& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; } + status_t isWideColorDisplay(const sp&, bool*) const override { return NO_ERROR; } protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 299499da12..61bf9090b4 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1158,6 +1158,20 @@ status_t SurfaceFlinger::uncacheBuffer(const sp& token, int32_t bufferI return NO_ERROR; } +status_t SurfaceFlinger::isWideColorDisplay(const sp& displayToken, + bool* outIsWideColorDisplay) const { + if (!displayToken || !outIsWideColorDisplay) { + return BAD_VALUE; + } + Mutex::Autolock _l(mStateLock); + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + return BAD_VALUE; + } + *outIsWideColorDisplay = display->hasWideColorGamut(); + return NO_ERROR; +} + status_t SurfaceFlinger::enableVSyncInjections(bool enable) { postMessageSync(new LambdaMessage([&] { Mutex::Autolock _l(mStateLock); @@ -4997,7 +5011,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_COMPOSITION_PREFERENCE: case GET_PROTECTED_CONTENT_SUPPORT: case CACHE_BUFFER: - case UNCACHE_BUFFER: { + case UNCACHE_BUFFER: + case IS_WIDE_COLOR_DISPLAY: { return OK; } case CAPTURE_LAYERS: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 68a602cf61..9cded31691 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -472,6 +472,8 @@ private: status_t cacheBuffer(const sp& token, const sp& buffer, int32_t* outBufferId) override; status_t uncacheBuffer(const sp& token, int32_t bufferId) override; + status_t isWideColorDisplay(const sp& displayToken, + bool* outIsWideColorDisplay) const override; /* ------------------------------------------------------------------------ * DeathRecipient interface diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 8560f5ed3e..48b2b807b1 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -19,6 +19,7 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using ui::ColorMode; namespace { const String8 DISPLAY_NAME("Credentials Display Test"); @@ -312,4 +313,36 @@ TEST_F(CredentialsTest, GetLayerDebugInfo) { seteuid(AID_BIN); ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers)); } + +TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { + sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + bool result = false; + status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result); + ASSERT_EQ(NO_ERROR, error); + bool hasWideColorMode = false; + Vector colorModes; + SurfaceComposerClient::getDisplayColorModes(display, &colorModes); + for (ColorMode colorMode : colorModes) { + switch (colorMode) { + case ColorMode::DISPLAY_P3: + case ColorMode::ADOBE_RGB: + case ColorMode::DCI_P3: + hasWideColorMode = true; + break; + default: + break; + } + } + ASSERT_EQ(hasWideColorMode, result); +} + +TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) { + sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + std::function condition = [=]() { + bool result = false; + return SurfaceComposerClient::isWideColorDisplay(display, &result); + }; + ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); +} + } // namespace android -- cgit v1.2.3-59-g8ed1b From b6888fab1d92285b150bebef15fb27a39b181e45 Mon Sep 17 00:00:00 2001 From: Peiyong Lin Date: Mon, 28 Jan 2019 13:20:58 -0800 Subject: Fix getProtectedContentSupport API. BUG: 117436546 Test: Build, flash and boot. Check returned value from SurfaceControl. Change-Id: I119be9e409b51e5055048bbc8fe28b4626cbbeeb --- libs/gui/ISurfaceComposer.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index a7e51e09a6..7195786ca8 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -687,13 +687,13 @@ public: virtual status_t getProtectedContentSupport(bool* outSupported) const { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply); - bool result; - status_t err = reply.readBool(&result); - if (err == NO_ERROR) { - *outSupported = result; + status_t error = + remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply); + if (error != NO_ERROR) { + return error; } - return err; + error = reply.readBool(outSupported); + return error; } virtual status_t cacheBuffer(const sp& token, const sp& buffer, @@ -1187,7 +1187,6 @@ status_t BnSurfaceComposer::onTransact( CHECK_INTERFACE(ISurfaceComposer, data, reply); bool result; status_t error = getProtectedContentSupport(&result); - reply->writeInt32(error); if (error == NO_ERROR) { reply->writeBool(result); } -- cgit v1.2.3-59-g8ed1b From 42d045637a71220d6539cf4e1ab9eb57c253324a Mon Sep 17 00:00:00 2001 From: Daniel Solomon Date: Sun, 20 Jan 2019 21:03:19 -0800 Subject: SurfaceFlinger: Add API to get native display color primaries Add getDisplayNativePrimaries(), used to get the coordinates of a display's native color primaries. Only a single internal display is supported at this time. This API makes use of an API by the same name added in Configstore v1.2. Bug: 123104704 Change-Id: I466f45f4a52b77d547f7b01164b93fb387a72780 --- libs/gui/ISurfaceComposer.cpp | 46 +++++++++ libs/gui/SurfaceComposerClient.cpp | 5 + libs/gui/include/gui/ISurfaceComposer.h | 4 + libs/gui/include/gui/SurfaceComposerClient.h | 5 + libs/gui/tests/Surface_test.cpp | 4 + libs/ui/Android.bp | 3 +- libs/ui/include/ui/ConfigStoreTypes.h | 29 ++++++ libs/ui/include_vndk/ui/ConfigStoreTypes.h | 29 ++++++ services/surfaceflinger/SurfaceFlinger.cpp | 55 +++++++++++ services/surfaceflinger/SurfaceFlinger.h | 8 ++ services/surfaceflinger/tests/Credentials_test.cpp | 9 ++ .../tests/unittests/DisplayTransactionTest.cpp | 110 +++++++++++++++++++++ .../tests/unittests/TestableSurfaceFlinger.h | 13 +++ 13 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 libs/ui/include/ui/ConfigStoreTypes.h create mode 100644 libs/ui/include_vndk/ui/ConfigStoreTypes.h (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 7195786ca8..bef68ef22f 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -395,6 +395,32 @@ public: return result; } + virtual status_t getDisplayNativePrimaries(const sp& display, + ui::DisplayPrimaries& primaries) { + Parcel data, reply; + status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (result != NO_ERROR) { + ALOGE("getDisplayNativePrimaries failed to writeInterfaceToken: %d", result); + return result; + } + result = data.writeStrongBinder(display); + if (result != NO_ERROR) { + ALOGE("getDisplayNativePrimaries failed to writeStrongBinder: %d", result); + return result; + } + result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES, data, &reply); + if (result != NO_ERROR) { + ALOGE("getDisplayNativePrimaries failed to transact: %d", result); + return result; + } + result = reply.readInt32(); + if (result == NO_ERROR) { + memcpy(&primaries, reply.readInplace(sizeof(ui::DisplayPrimaries)), + sizeof(ui::DisplayPrimaries)); + } + return result; + } + virtual ColorMode getActiveColorMode(const sp& display) { Parcel data, reply; status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); @@ -974,6 +1000,26 @@ status_t BnSurfaceComposer::onTransact( } return NO_ERROR; } + case GET_DISPLAY_NATIVE_PRIMARIES: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + ui::DisplayPrimaries primaries; + sp display = nullptr; + + status_t result = data.readStrongBinder(&display); + if (result != NO_ERROR) { + ALOGE("getDisplayNativePrimaries failed to readStrongBinder: %d", result); + return result; + } + + result = getDisplayNativePrimaries(display, primaries); + reply->writeInt32(result); + if (result == NO_ERROR) { + memcpy(reply->writeInplace(sizeof(ui::DisplayPrimaries)), &primaries, + sizeof(ui::DisplayPrimaries)); + } + + return NO_ERROR; + } case GET_ACTIVE_COLOR_MODE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = nullptr; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index a5d43c0cbe..c712bde97d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1297,6 +1297,11 @@ status_t SurfaceComposerClient::getDisplayColorModes(const sp& display, return ComposerService::getComposerService()->getDisplayColorModes(display, outColorModes); } +status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp& display, + ui::DisplayPrimaries& outPrimaries) { + return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries); +} + ColorMode SurfaceComposerClient::getActiveColorMode(const sp& display) { return ComposerService::getComposerService()->getActiveColorMode(display); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index bbfc8c45fc..3899f6a3d0 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -27,6 +27,7 @@ #include +#include #include #include #include @@ -161,6 +162,8 @@ public: virtual status_t getDisplayColorModes(const sp& display, Vector* outColorModes) = 0; + virtual status_t getDisplayNativePrimaries(const sp& display, + ui::DisplayPrimaries& primaries) = 0; virtual ui::ColorMode getActiveColorMode(const sp& display) = 0; virtual status_t setActiveColorMode(const sp& display, ui::ColorMode colorMode) = 0; @@ -373,6 +376,7 @@ public: CACHE_BUFFER, UNCACHE_BUFFER, IS_WIDE_COLOR_DISPLAY, + GET_DISPLAY_NATIVE_PRIMARIES, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index ef3b2e68d3..8e2bb2b6e6 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include @@ -114,6 +115,10 @@ public: static status_t getDisplayColorModes(const sp& display, Vector* outColorModes); + // Get the coordinates of the display's native color primaries + static status_t getDisplayNativePrimaries(const sp& display, + ui::DisplayPrimaries& outPrimaries); + // Gets the active color mode for the given display static ui::ColorMode getActiveColorMode(const sp& display); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index d525a338db..1705fd7383 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -598,6 +598,10 @@ public: Vector* /*outColorModes*/) override { return NO_ERROR; } + status_t getDisplayNativePrimaries(const sp& /*display*/, + ui::DisplayPrimaries& /*primaries*/) override { + return NO_ERROR; + } ColorMode getActiveColorMode(const sp& /*display*/) override { return ColorMode::NATIVE; diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 74450d7fbf..00e227fe20 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -87,7 +87,7 @@ cc_library_shared { "android.hardware.graphics.mapper@2.0", "android.hardware.graphics.mapper@2.1", "android.hardware.graphics.mapper@3.0", - "android.hardware.configstore@1.0", + "android.hardware.configstore@1.2", "android.hardware.configstore-utils", "libbase", "libcutils", @@ -102,6 +102,7 @@ cc_library_shared { ], export_shared_lib_headers: [ + "android.hardware.configstore@1.2", "android.hardware.graphics.common@1.2", ], diff --git a/libs/ui/include/ui/ConfigStoreTypes.h b/libs/ui/include/ui/ConfigStoreTypes.h new file mode 100644 index 0000000000..37a2bd5451 --- /dev/null +++ b/libs/ui/include/ui/ConfigStoreTypes.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +// android::ui::* in this header file will alias different types as +// the HIDL interface is updated. +namespace android { +namespace ui { + +using android::hardware::configstore::V1_2::DisplayPrimaries; + +} // namespace ui +} // namespace android diff --git a/libs/ui/include_vndk/ui/ConfigStoreTypes.h b/libs/ui/include_vndk/ui/ConfigStoreTypes.h new file mode 100644 index 0000000000..37a2bd5451 --- /dev/null +++ b/libs/ui/include_vndk/ui/ConfigStoreTypes.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +// android::ui::* in this header file will alias different types as +// the HIDL interface is updated. +namespace android { +namespace ui { + +using android::hardware::configstore::V1_2::DisplayPrimaries; + +} // namespace ui +} // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index acf00139ce..c6297439b9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -122,6 +122,7 @@ using namespace android::sysprop; using base::StringAppendF; using ui::ColorMode; using ui::Dataspace; +using ui::DisplayPrimaries; using ui::Hdr; using ui::RenderIntent; @@ -196,6 +197,19 @@ const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER" const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER"); const String16 sDump("android.permission.DUMP"); +constexpr float kSrgbRedX = 0.4123f; +constexpr float kSrgbRedY = 0.2126f; +constexpr float kSrgbRedZ = 0.0193f; +constexpr float kSrgbGreenX = 0.3576f; +constexpr float kSrgbGreenY = 0.7152f; +constexpr float kSrgbGreenZ = 0.1192f; +constexpr float kSrgbBlueX = 0.1805f; +constexpr float kSrgbBlueY = 0.0722f; +constexpr float kSrgbBlueZ = 0.9506f; +constexpr float kSrgbWhiteX = 0.9505f; +constexpr float kSrgbWhiteY = 1.0000f; +constexpr float kSrgbWhiteZ = 1.0891f; + // --------------------------------------------------------------------------- int64_t SurfaceFlinger::vsyncPhaseOffsetNs; int64_t SurfaceFlinger::sfVsyncPhaseOffsetNs; @@ -340,6 +354,16 @@ SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory) getFactory().createDispSync("PrimaryDispSync", SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset); + auto surfaceFlingerConfigsServiceV1_2 = V1_2::ISurfaceFlingerConfigs::getService(); + if (surfaceFlingerConfigsServiceV1_2) { + surfaceFlingerConfigsServiceV1_2->getDisplayNativePrimaries( + [&](auto tmpPrimaries) { + memcpy(&mInternalDisplayPrimaries, &tmpPrimaries, sizeof(ui::DisplayPrimaries)); + }); + } else { + initDefaultDisplayNativePrimaries(); + } + // debugging stuff... char value[PROPERTY_VALUE_MAX]; @@ -1012,6 +1036,21 @@ status_t SurfaceFlinger::getDisplayColorModes(const sp& displayToken, return NO_ERROR; } +status_t SurfaceFlinger::getDisplayNativePrimaries(const sp& displayToken, + ui::DisplayPrimaries &primaries) { + if (!displayToken) { + return BAD_VALUE; + } + + // Currently we only support this API for a single internal display. + if (getInternalDisplayToken() != displayToken) { + return BAD_VALUE; + } + + memcpy(&primaries, &mInternalDisplayPrimaries, sizeof(ui::DisplayPrimaries)); + return NO_ERROR; +} + ColorMode SurfaceFlinger::getActiveColorMode(const sp& displayToken) { if (const auto display = getDisplayDevice(displayToken)) { return display->getCompositionDisplay()->getState().colorMode; @@ -3190,6 +3229,21 @@ void SurfaceFlinger::invalidateLayerStack(const sp& layer, const Re } } +void SurfaceFlinger::initDefaultDisplayNativePrimaries() { + mInternalDisplayPrimaries.red.X = kSrgbRedX; + mInternalDisplayPrimaries.red.Y = kSrgbRedY; + mInternalDisplayPrimaries.red.Z = kSrgbRedZ; + mInternalDisplayPrimaries.green.X = kSrgbGreenX; + mInternalDisplayPrimaries.green.Y = kSrgbGreenY; + mInternalDisplayPrimaries.green.Z = kSrgbGreenZ; + mInternalDisplayPrimaries.blue.X = kSrgbBlueX; + mInternalDisplayPrimaries.blue.Y = kSrgbBlueY; + mInternalDisplayPrimaries.blue.Z = kSrgbBlueZ; + mInternalDisplayPrimaries.white.X = kSrgbWhiteX; + mInternalDisplayPrimaries.white.Y = kSrgbWhiteY; + mInternalDisplayPrimaries.white.Z = kSrgbWhiteZ; +} + bool SurfaceFlinger::handlePageFlip() { ALOGV("handlePageFlip"); @@ -4975,6 +5029,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_ACTIVE_CONFIG: case GET_BUILT_IN_DISPLAY: case GET_DISPLAY_COLOR_MODES: + case GET_DISPLAY_NATIVE_PRIMARIES: case GET_DISPLAY_CONFIGS: case GET_DISPLAY_STATS: case GET_SUPPORTED_FRAME_TIMESTAMPS: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4d84144b5e..b051b0db95 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -438,6 +438,8 @@ private: int getActiveConfig(const sp& displayToken) override; status_t getDisplayColorModes(const sp& displayToken, Vector* configs) override; + status_t getDisplayNativePrimaries(const sp& displayToken, + ui::DisplayPrimaries &primaries); ui::ColorMode getActiveColorMode(const sp& displayToken) override; status_t setActiveColorMode(const sp& displayToken, ui::ColorMode colorMode) override; void setPowerMode(const sp& displayToken, int mode) override; @@ -663,6 +665,10 @@ private: // region of all screens presenting this layer stack. void invalidateLayerStack(const sp& layer, const Region& dirty); + // Initialize structures containing information about the internal + // display's native color coordinates using default data + void initDefaultDisplayNativePrimaries(); + /* ------------------------------------------------------------------------ * H/W composer */ @@ -1083,6 +1089,8 @@ private: InputWindowCommands mInputWindowCommands; BufferStateLayerCache mBufferStateLayerCache; + + ui::DisplayPrimaries mInternalDisplayPrimaries; }; }; // namespace android diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index 48b2b807b1..f021d3dfa7 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -207,6 +207,15 @@ TEST_F(CredentialsTest, GetDisplayColorModesTest) { ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); } +TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) { + sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + std::function condition = [=]() { + ui::DisplayPrimaries primaries; + return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries); + }; + ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, NO_ERROR, NO_ERROR)); +} + TEST_F(CredentialsTest, SetActiveConfigTest) { sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); std::function condition = [=]() { diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 2c1833bb8f..4cb79ab495 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -1225,6 +1225,116 @@ TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) { ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent); } +/* ------------------------------------------------------------------------ + * SurfaceFlinger::getDisplayNativePrimaries + */ + +class GetDisplayNativePrimaries : public DisplayTransactionTest { +public: + GetDisplayNativePrimaries(); + void populateDummyDisplayNativePrimaries(ui::DisplayPrimaries& primaries); + void checkDummyDisplayNativePrimaries(const ui::DisplayPrimaries& primaries); + +private: + static constexpr float mStartingTestValue = 1.0f; +}; + +GetDisplayNativePrimaries::GetDisplayNativePrimaries() { + SimplePrimaryDisplayCase::Display::injectHwcDisplay(this); + injectFakeNativeWindowSurfaceFactory(); +} + +void GetDisplayNativePrimaries::populateDummyDisplayNativePrimaries( + ui::DisplayPrimaries& primaries) { + float startingVal = mStartingTestValue; + primaries.red.X = startingVal++; + primaries.red.Y = startingVal++; + primaries.red.Z = startingVal++; + primaries.green.X = startingVal++; + primaries.green.Y = startingVal++; + primaries.green.Z = startingVal++; + primaries.blue.X = startingVal++; + primaries.blue.Y = startingVal++; + primaries.blue.Z = startingVal++; + primaries.white.X = startingVal++; + primaries.white.Y = startingVal++; + primaries.white.Z = startingVal++; +} + +void GetDisplayNativePrimaries::checkDummyDisplayNativePrimaries( + const ui::DisplayPrimaries& primaries) { + float startingVal = mStartingTestValue; + EXPECT_EQ(primaries.red.X, startingVal++); + EXPECT_EQ(primaries.red.Y, startingVal++); + EXPECT_EQ(primaries.red.Z, startingVal++); + EXPECT_EQ(primaries.green.X, startingVal++); + EXPECT_EQ(primaries.green.Y, startingVal++); + EXPECT_EQ(primaries.green.Z, startingVal++); + EXPECT_EQ(primaries.blue.X, startingVal++); + EXPECT_EQ(primaries.blue.Y, startingVal++); + EXPECT_EQ(primaries.blue.Z, startingVal++); + EXPECT_EQ(primaries.white.X, startingVal++); + EXPECT_EQ(primaries.white.Y, startingVal++); + EXPECT_EQ(primaries.white.Z, startingVal++); +} + +TEST_F(GetDisplayNativePrimaries, nullDisplayToken) { + ui::DisplayPrimaries primaries; + EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries)); +} + +TEST_F(GetDisplayNativePrimaries, internalDisplayWithDefaultPrimariesData) { + auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this); + injector.inject(); + auto internalDisplayToken = injector.token(); + // A nullptr would trigger a different execution path than what's being tested here + EXPECT_NE(nullptr, internalDisplayToken.get()); + + mFlinger.initDefaultDisplayNativePrimaries(); + + ui::DisplayPrimaries primaries; + // Expecting sRGB primaries + EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries)); + EXPECT_EQ(primaries.red.X, 0.4123f); + EXPECT_EQ(primaries.red.Y, 0.2126f); + EXPECT_EQ(primaries.red.Z, 0.0193f); + EXPECT_EQ(primaries.green.X, 0.3576f); + EXPECT_EQ(primaries.green.Y, 0.7152f); + EXPECT_EQ(primaries.green.Z, 0.1192f); + EXPECT_EQ(primaries.blue.X, 0.1805f); + EXPECT_EQ(primaries.blue.Y, 0.0722f); + EXPECT_EQ(primaries.blue.Z, 0.9506f); + EXPECT_EQ(primaries.white.X, 0.9505f); + EXPECT_EQ(primaries.white.Y, 1.0000f); + EXPECT_EQ(primaries.white.Z, 1.0891f); +} + +TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) { + auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this); + injector.inject(); + auto internalDisplayToken = injector.token(); + + ui::DisplayPrimaries expectedPrimaries; + populateDummyDisplayNativePrimaries(expectedPrimaries); + mFlinger.setInternalDisplayPrimaries(expectedPrimaries); + + ui::DisplayPrimaries primaries; + EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries)); + + checkDummyDisplayNativePrimaries(primaries); +} + +TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) { + sp notInternalDisplayToken = new BBinder(); + + ui::DisplayPrimaries primaries; + populateDummyDisplayNativePrimaries(primaries); + EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries)); + + // Check primaries argument wasn't modified in case of failure + checkDummyDisplayNativePrimaries(primaries); +} + /* ------------------------------------------------------------------------ * SurfaceFlinger::setupNewDisplayDeviceInternal */ diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 9c5c9670b1..b9b0cf89d8 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -187,6 +187,10 @@ public: mFactory.mCreateNativeWindowSurface = f; } + void setInternalDisplayPrimaries(const ui::DisplayPrimaries& primaries) { + memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries)); + } + using HotplugEvent = SurfaceFlinger::HotplugEvent; auto& mutableLayerCurrentState(sp layer) { return layer->mCurrentState; } @@ -260,6 +264,15 @@ public: return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, visitor); } + auto getDisplayNativePrimaries(const sp& displayToken, + ui::DisplayPrimaries &primaries) { + return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); + } + + void initDefaultDisplayNativePrimaries() { + mFlinger->SurfaceFlinger::initDefaultDisplayNativePrimaries(); + } + /* ------------------------------------------------------------------------ * Read-only access to private data to assert post-conditions. */ -- cgit v1.2.3-59-g8ed1b From dcb38bbd32eb96ec46d69658390353a853b3af6d Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Fri, 25 Jan 2019 02:35:50 -0800 Subject: SF: Plumb physical display IDs to libgui This CL replaces ISurfaceComposer::{eDisplayIdMain,eDisplayIdHdmi} with the stable 64-bit display IDs generated by SF. Note that the 64-bit IDs fall back to the old values if the HWC API for display identification is not supported. Bug: 74619554 Test: LocalDisplayAdapter and Choreographer receive 64-bit IDs Test: 64-bit IDs fall back to 0 and 1 on HWC 2.2 and below Change-Id: I3c08eff6eb8bb179ecce596ab2820a2aa44c8649 --- cmds/flatland/GLHelper.cpp | 4 +- libs/gui/ISurfaceComposer.cpp | 35 ++++-- libs/gui/Surface.cpp | 14 ++- libs/gui/SurfaceComposerClient.cpp | 16 ++- libs/gui/include/gui/DisplayEventReceiver.h | 2 +- libs/gui/include/gui/ISurfaceComposer.h | 33 ++++-- libs/gui/include/gui/SurfaceComposerClient.h | 10 +- libs/gui/tests/DisplayedContentSampling_test.cpp | 2 +- libs/gui/tests/EndToEndNativeInputTest.cpp | 6 +- libs/gui/tests/Surface_test.cpp | 9 +- libs/ui/include/ui/GraphicTypes.h | 10 +- opengl/tests/lib/WindowSurface.cpp | 8 +- .../DisplayHardware/DisplayIdentification.h | 4 +- services/surfaceflinger/Scheduler/EventThread.cpp | 26 +++-- services/surfaceflinger/Scheduler/EventThread.h | 13 +-- services/surfaceflinger/Scheduler/Scheduler.cpp | 5 +- services/surfaceflinger/Scheduler/Scheduler.h | 4 +- services/surfaceflinger/SurfaceFlinger.cpp | 128 +++++++++++---------- services/surfaceflinger/SurfaceFlinger.h | 31 +++-- services/surfaceflinger/tests/Credentials_test.cpp | 30 ++--- .../tests/SurfaceInterceptor_test.cpp | 8 +- services/surfaceflinger/tests/Transaction_test.cpp | 24 ++-- .../tests/fakehwc/SFFakeHwc_test.cpp | 52 +++++---- .../tests/unittests/DisplayTransactionTest.cpp | 29 +++-- .../tests/unittests/EventThreadTest.cpp | 42 +++---- .../tests/unittests/SchedulerTest.cpp | 16 +-- .../tests/unittests/mock/MockEventThread.h | 2 +- 27 files changed, 323 insertions(+), 240 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp index 62d2fa1548..d398559ee8 100644 --- a/cmds/flatland/GLHelper.cpp +++ b/cmds/flatland/GLHelper.cpp @@ -222,9 +222,9 @@ bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, } bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) { - sp dpy = mSurfaceComposerClient->getBuiltInDisplay(0); + const sp dpy = mSurfaceComposerClient->getInternalDisplayToken(); if (dpy == nullptr) { - fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n"); + fprintf(stderr, "SurfaceComposer::getInternalDisplayToken failed.\n"); return false; } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index bef68ef22f..4357f798df 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -275,12 +275,25 @@ public: remote()->transact(BnSurfaceComposer::DESTROY_DISPLAY, data, &reply); } - virtual sp getBuiltInDisplay(int32_t id) - { + virtual std::vector getPhysicalDisplayIds() const { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS, data, &reply) == + NO_ERROR) { + std::vector displayIds; + if (reply.readUint64Vector(&displayIds) == NO_ERROR) { + return displayIds; + } + } + + return {}; + } + + virtual sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeInt32(id); - remote()->transact(BnSurfaceComposer::GET_BUILT_IN_DISPLAY, data, &reply); + data.writeUint64(displayId); + remote()->transact(BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN, data, &reply); return reply.readStrongBinder(); } @@ -932,10 +945,10 @@ status_t BnSurfaceComposer::onTransact( destroyDisplay(display); return NO_ERROR; } - case GET_BUILT_IN_DISPLAY: { + case GET_PHYSICAL_DISPLAY_TOKEN: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t id = data.readInt32(); - sp display(getBuiltInDisplay(id)); + PhysicalDisplayId displayId = data.readUint64(); + sp display = getPhysicalDisplayToken(displayId); reply->writeStrongBinder(display); return NO_ERROR; } @@ -1294,12 +1307,14 @@ status_t BnSurfaceComposer::onTransact( } return error; } + case GET_PHYSICAL_DISPLAY_IDS: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + return reply->writeUint64Vector(getPhysicalDisplayIds()); + } default: { return BBinder::onTransact(code, data, reply, flags); } } } -// ---------------------------------------------------------------------------- - -}; +} // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 1f726b2ba4..3affa23482 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -321,8 +321,11 @@ status_t Surface::getFrameTimestamps(uint64_t frameNumber, status_t Surface::getWideColorSupport(bool* supported) { ATRACE_CALL(); - sp display( - composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const sp display = composerService()->getInternalDisplayToken(); + if (display == nullptr) { + return NAME_NOT_FOUND; + } + *supported = false; status_t error = composerService()->isWideColorDisplay(display, supported); return error; @@ -331,8 +334,11 @@ status_t Surface::getWideColorSupport(bool* supported) { status_t Surface::getHdrSupport(bool* supported) { ATRACE_CALL(); - sp display( - composerService()->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const sp display = composerService()->getInternalDisplayToken(); + if (display == nullptr) { + return NAME_NOT_FOUND; + } + HdrCapabilities hdrCapabilities; status_t err = composerService()->getHdrCapabilities(display, &hdrCapabilities); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c712bde97d..90656d60c7 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -374,8 +374,20 @@ void SurfaceComposerClient::destroyDisplay(const sp& display) { return ComposerService::getComposerService()->destroyDisplay(display); } -sp SurfaceComposerClient::getBuiltInDisplay(int32_t id) { - return ComposerService::getComposerService()->getBuiltInDisplay(id); +std::vector SurfaceComposerClient::getPhysicalDisplayIds() { + return ComposerService::getComposerService()->getPhysicalDisplayIds(); +} + +std::optional SurfaceComposerClient::getInternalDisplayId() { + return ComposerService::getComposerService()->getInternalDisplayId(); +} + +sp SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) { + return ComposerService::getComposerService()->getPhysicalDisplayToken(displayId); +} + +sp SurfaceComposerClient::getInternalDisplayToken() { + return ComposerService::getComposerService()->getInternalDisplayToken(); } void SurfaceComposerClient::Transaction::setAnimationTransaction() { diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index a4102dfe03..8c3f46305c 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -58,7 +58,7 @@ public: struct Header { uint32_t type; - uint32_t id; + PhysicalDisplayId displayId; nsecs_t timestamp __attribute__((aligned(8))); }; diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 3899f6a3d0..9d6b8729d0 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -34,6 +34,7 @@ #include #include +#include #include namespace android { @@ -71,11 +72,6 @@ public: eEarlyWakeup = 0x04 }; - enum { - eDisplayIdMain = 0, - eDisplayIdHdmi = 1 - }; - enum Rotation { eRotateNone = 0, eRotate90 = 1, @@ -88,7 +84,7 @@ public: eVsyncSourceSurfaceFlinger = 1 }; - /* + /* * Create a connection with SurfaceFlinger. */ virtual sp createConnection() = 0; @@ -108,10 +104,26 @@ public: */ virtual void destroyDisplay(const sp& display) = 0; - /* get the token for the existing default displays. possible values - * for id are eDisplayIdMain and eDisplayIdHdmi. + /* get stable IDs for connected physical displays. + */ + virtual std::vector getPhysicalDisplayIds() const = 0; + + // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic. + std::optional getInternalDisplayId() const { + const auto displayIds = getPhysicalDisplayIds(); + return displayIds.empty() ? std::nullopt : std::make_optional(displayIds.front()); + } + + /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a + * DisplayEventReceiver hotplug event. */ - virtual sp getBuiltInDisplay(int32_t id) = 0; + virtual sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const = 0; + + // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic. + sp getInternalDisplayToken() const { + const auto displayId = getInternalDisplayId(); + return displayId ? getPhysicalDisplayToken(*displayId) : nullptr; + } /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual void setTransactionState(const Vector& state, @@ -346,7 +358,7 @@ public: CREATE_DISPLAY_EVENT_CONNECTION, CREATE_DISPLAY, DESTROY_DISPLAY, - GET_BUILT_IN_DISPLAY, + GET_PHYSICAL_DISPLAY_TOKEN, SET_TRANSACTION_STATE, AUTHENTICATE_SURFACE, GET_SUPPORTED_FRAME_TIMESTAMPS, @@ -377,6 +389,7 @@ public: UNCACHE_BUFFER, IS_WIDE_COLOR_DISPLAY, GET_DISPLAY_NATIVE_PRIMARIES, + GET_PHYSICAL_DISPLAY_IDS, // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 8e2bb2b6e6..f92c0fe547 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -202,9 +202,13 @@ public: //! Destroy a virtual display static void destroyDisplay(const sp& display); - //! Get the token for the existing default displays. - //! Possible values for id are eDisplayIdMain and eDisplayIdHdmi. - static sp getBuiltInDisplay(int32_t id); + //! Get stable IDs for connected physical displays + static std::vector getPhysicalDisplayIds(); + static std::optional getInternalDisplayId(); + + //! Get token for a physical display given its stable ID + static sp getPhysicalDisplayToken(PhysicalDisplayId displayId); + static sp getInternalDisplayToken(); static status_t enableVSyncInjections(bool enable); diff --git a/libs/gui/tests/DisplayedContentSampling_test.cpp b/libs/gui/tests/DisplayedContentSampling_test.cpp index 5443812bff..b647aaba8f 100644 --- a/libs/gui/tests/DisplayedContentSampling_test.cpp +++ b/libs/gui/tests/DisplayedContentSampling_test.cpp @@ -32,7 +32,7 @@ protected: void SetUp() { mComposerClient = new SurfaceComposerClient; ASSERT_EQ(OK, mComposerClient->initCheck()); - mDisplayToken = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); + mDisplayToken = mComposerClient->getInternalDisplayToken(); ASSERT_TRUE(mDisplayToken); } diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index ac97733508..4a7848020f 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -233,9 +233,11 @@ public: mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); + const auto display = mComposerClient->getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + DisplayInfo info; - auto display = mComposerClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); - SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(NO_ERROR, mComposerClient->getDisplayInfo(display, &info)); // After a new buffer is queued, SurfaceFlinger is notified and will // latch the new buffer on next vsync. Let's heuristically wait for 3 diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 1705fd7383..ca58574e95 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -131,8 +131,10 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { // Verify the screenshot works with no protected buffers. sp sf(ComposerService::getComposerService()); - sp display(sf->getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain)); + + const sp display = sf->getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + sp outBuffer; ASSERT_EQ(NO_ERROR, sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB, @@ -552,7 +554,8 @@ public: sp createDisplay(const String8& /*displayName*/, bool /*secure*/) override { return nullptr; } void destroyDisplay(const sp& /*display */) override {} - sp getBuiltInDisplay(int32_t /*id*/) override { return nullptr; } + std::vector getPhysicalDisplayIds() const override { return {}; } + sp getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; } void setTransactionState(const Vector& /*state*/, const Vector& /*displays*/, uint32_t /*flags*/, const sp& /*applyToken*/, diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h index 4b03e44978..5dc56c8181 100644 --- a/libs/ui/include/ui/GraphicTypes.h +++ b/libs/ui/include/ui/GraphicTypes.h @@ -16,13 +16,21 @@ #pragma once +#include +#include + #include #include #include +#define ANDROID_PHYSICAL_DISPLAY_ID_FORMAT PRIu64 + +namespace android { + +using PhysicalDisplayId = uint64_t; + // android::ui::* in this header file will alias different types as // the HIDL interface is updated. -namespace android { namespace ui { using android::hardware::graphics::common::V1_1::RenderIntent; diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp index b06422a98c..a0bd4e2409 100644 --- a/opengl/tests/lib/WindowSurface.cpp +++ b/opengl/tests/lib/WindowSurface.cpp @@ -34,8 +34,12 @@ WindowSurface::WindowSurface() { } // Get main display parameters. - sp mainDpy = SurfaceComposerClient::getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain); + const auto mainDpy = SurfaceComposerClient::getInternalDisplayToken(); + if (mainDpy == nullptr) { + fprintf(stderr, "ERROR: no display\n"); + return; + } + DisplayInfo mainDpyInfo; err = SurfaceComposerClient::getDisplayInfo(mainDpy, &mainDpyInfo); if (err != NO_ERROR) { diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h index 1599995297..d63cd79b03 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h +++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h @@ -23,10 +23,12 @@ #include #include +#include + namespace android { struct DisplayId { - using Type = uint64_t; + using Type = PhysicalDisplayId; Type value; uint16_t manufacturerId() const; diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 52abe9ca38..91ae087adb 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -69,24 +69,28 @@ std::string toString(const EventThreadConnection& connection) { std::string toString(const DisplayEventReceiver::Event& event) { switch (event.header.type) { case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: - return StringPrintf("Hotplug{displayId=%u, %s}", event.header.id, + return StringPrintf("Hotplug{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", %s}", + event.header.displayId, event.hotplug.connected ? "connected" : "disconnected"); case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: - return StringPrintf("VSync{displayId=%u, count=%u}", event.header.id, - event.vsync.count); + return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT + ", count=%u}", + event.header.displayId, event.vsync.count); default: return "Event{}"; } } -DisplayEventReceiver::Event makeHotplug(uint32_t displayId, nsecs_t timestamp, bool connected) { +DisplayEventReceiver::Event makeHotplug(PhysicalDisplayId displayId, nsecs_t timestamp, + bool connected) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, displayId, timestamp}; event.hotplug.connected = connected; return event; } -DisplayEventReceiver::Event makeVSync(uint32_t displayId, nsecs_t timestamp, uint32_t count) { +DisplayEventReceiver::Event makeVSync(PhysicalDisplayId displayId, nsecs_t timestamp, + uint32_t count) { DisplayEventReceiver::Event event; event.header = {DisplayEventReceiver::DISPLAY_EVENT_VSYNC, displayId, timestamp}; event.vsync.count = count; @@ -290,10 +294,9 @@ void EventThread::onVSyncEvent(nsecs_t timestamp) { mCondition.notify_all(); } -void EventThread::onHotplugReceived(DisplayType displayType, bool connected) { +void EventThread::onHotplugReceived(PhysicalDisplayId displayId, bool connected) { std::lock_guard lock(mMutex); - const uint32_t displayId = displayType == DisplayType::Primary ? 0 : 1; mPendingEvents.push_back(makeHotplug(displayId, systemTime(), connected)); mCondition.notify_all(); } @@ -312,9 +315,9 @@ void EventThread::threadMain(std::unique_lock& lock) { switch (event->header.type) { case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG: if (event->hotplug.connected && !mVSyncState) { - mVSyncState.emplace(event->header.id); + mVSyncState.emplace(event->header.displayId); } else if (!event->hotplug.connected && mVSyncState && - mVSyncState->displayId == event->header.id) { + mVSyncState->displayId == event->header.displayId) { mVSyncState.reset(); } break; @@ -440,8 +443,9 @@ void EventThread::dump(std::string& result) const { StringAppendF(&result, "%s: state=%s VSyncState=", mThreadName, toCString(mState)); if (mVSyncState) { - StringAppendF(&result, "{displayId=%u, count=%u%s}\n", mVSyncState->displayId, - mVSyncState->count, mVSyncState->synthetic ? ", synthetic" : ""); + StringAppendF(&result, "{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%u%s}\n", + mVSyncState->displayId, mVSyncState->count, + mVSyncState->synthetic ? ", synthetic" : ""); } else { StringAppendF(&result, "none\n"); } diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 89b799e59f..62b6a8b65f 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -94,9 +94,6 @@ private: class EventThread { public: - // TODO: Remove once stable display IDs are plumbed through SF/WM interface. - enum class DisplayType { Primary, External }; - virtual ~EventThread(); virtual sp createEventConnection( @@ -108,8 +105,7 @@ public: // called after the screen is turned on from main thread virtual void onScreenAcquired() = 0; - // called when receiving a hotplug event - virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0; + virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0; virtual void dump(std::string& result) const = 0; @@ -151,8 +147,7 @@ public: // called after the screen is turned on from main thread void onScreenAcquired() override; - // called when receiving a hotplug event - void onHotplugReceived(DisplayType displayType, bool connected) override; + void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override; void dump(std::string& result) const override; @@ -199,9 +194,9 @@ private: // VSYNC state of connected display. struct VSyncState { - explicit VSyncState(uint32_t displayId) : displayId(displayId) {} + explicit VSyncState(PhysicalDisplayId displayId) : displayId(displayId) {} - const uint32_t displayId; + const PhysicalDisplayId displayId; // Number of VSYNC events since display was connected. uint32_t count = 0; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 00820f15fd..a29877e884 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -128,9 +127,9 @@ sp Scheduler::getEventConnection(const sp& handle, - EventThread::DisplayType displayType, bool connected) { + PhysicalDisplayId displayId, bool connected) { RETURN_IF_INVALID(); - mConnections[handle->id]->thread->onHotplugReceived(displayType, connected); + mConnections[handle->id]->thread->onHotplugReceived(displayId, connected); } void Scheduler::onScreenAcquired(const sp& handle) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index b7176050a7..e77dc06c34 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -19,8 +19,8 @@ #include #include -#include #include +#include #include "DispSync.h" #include "EventControlThread.h" @@ -85,7 +85,7 @@ public: sp getEventConnection(const sp& handle); // Should be called when receiving a hotplug event. - void hotplugReceived(const sp& handle, EventThread::DisplayType displayType, + void hotplugReceived(const sp& handle, PhysicalDisplayId displayId, bool connected); // Should be called after the screen is turned on. diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2cf2cd8a5d..4c1b267397 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -496,21 +496,30 @@ void SurfaceFlinger::destroyDisplay(const sp& displayToken) { setTransactionFlags(eDisplayTransactionNeeded); } -sp SurfaceFlinger::getBuiltInDisplay(int32_t id) { - std::optional displayId; +std::vector SurfaceFlinger::getPhysicalDisplayIds() const { + Mutex::Autolock lock(mStateLock); - if (id == HWC_DISPLAY_PRIMARY) { - displayId = getInternalDisplayId(); - } else if (id == HWC_DISPLAY_EXTERNAL) { - displayId = getExternalDisplayId(); + const auto internalDisplayId = getInternalDisplayIdLocked(); + if (!internalDisplayId) { + return {}; } - if (!displayId) { - ALOGE("%s: Invalid display %d", __FUNCTION__, id); - return nullptr; + std::vector displayIds; + displayIds.reserve(mPhysicalDisplayTokens.size()); + displayIds.push_back(internalDisplayId->value); + + for (const auto& [id, token] : mPhysicalDisplayTokens) { + if (id != *internalDisplayId) { + displayIds.push_back(id.value); + } } - return getPhysicalDisplayToken(*displayId); + return displayIds; +} + +sp SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const { + Mutex::Autolock lock(mStateLock); + return getPhysicalDisplayTokenLocked(DisplayId{displayId}); } status_t SurfaceFlinger::getColorManagement(bool* outGetColorManagement) const { @@ -614,9 +623,9 @@ void SurfaceFlinger::init() { // start the EventThread if (mUseScheduler) { - mScheduler = getFactory().createScheduler([this](bool enabled) { - setVsyncEnabled(EventThread::DisplayType::Primary, enabled); - }); + mScheduler = getFactory().createScheduler( + [this](bool enabled) { setPrimaryVsyncEnabled(enabled); }); + // TODO(b/113612090): Currently we assume that if scheduler is turned on, then the refresh // rate is 90. Once b/122905403 is completed, this should be updated accordingly. mPhaseOffsets->setRefreshRateType( @@ -705,7 +714,7 @@ void SurfaceFlinger::init() { } mEventControlThread = getFactory().createEventControlThread( - [this](bool enabled) { setVsyncEnabled(EventThread::DisplayType::Primary, enabled); }); + [this](bool enabled) { setPrimaryVsyncEnabled(enabled); }); // initialize our drawing state mDrawingState = mCurrentState; @@ -820,7 +829,9 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, return BAD_VALUE; } - const auto displayId = getPhysicalDisplayId(displayToken); + ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); + + const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { return NAME_NOT_FOUND; } @@ -844,8 +855,6 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, configs->clear(); - ConditionalLock _l(mStateLock, - std::this_thread::get_id() != mMainThreadId); for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) { DisplayInfo info = DisplayInfo(); @@ -858,7 +867,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, info.viewportW = info.w; info.viewportH = info.h; - if (displayId == getInternalDisplayId()) { + if (displayId == getInternalDisplayIdLocked()) { // The density of the device is provided by a build property float density = Density::getBuildDensity() / 160.0f; if (density == 0) { @@ -914,7 +923,7 @@ status_t SurfaceFlinger::getDisplayConfigs(const sp& displayToken, // All non-virtual displays are currently considered secure. info.secure = true; - if (displayId == getInternalDisplayId() && + if (displayId == getInternalDisplayIdLocked() && primaryDisplayOrientation & DisplayState::eOrientationSwapMask) { std::swap(info.w, info.h); } @@ -1012,15 +1021,15 @@ status_t SurfaceFlinger::getDisplayColorModes(const sp& displayToken, return BAD_VALUE; } - const auto displayId = getPhysicalDisplayId(displayToken); - if (!displayId) { - return NAME_NOT_FOUND; - } - std::vector modes; { - ConditionalLock _l(mStateLock, - std::this_thread::get_id() != mMainThreadId); + ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); + + const auto displayId = getPhysicalDisplayIdLocked(displayToken); + if (!displayId) { + return NAME_NOT_FOUND; + } + modes = getHwComposer().getColorModes(*displayId); } outColorModes->clear(); @@ -1330,7 +1339,7 @@ void SurfaceFlinger::run() { } nsecs_t SurfaceFlinger::getVsyncPeriod() const { - const auto displayId = getInternalDisplayId(); + const auto displayId = getInternalDisplayIdLocked(); if (!displayId || !getHwComposer().isConnected(*displayId)) { return 0; } @@ -1447,9 +1456,10 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -void SurfaceFlinger::setRefreshRateTo(float newFps) { - const auto displayId = getInternalDisplayId(); - if (!displayId || mBootStage != BootStage::FINISHED) { +// TODO(b/123715322): Fix thread safety. +void SurfaceFlinger::setRefreshRateTo(float newFps) NO_THREAD_SAFETY_ANALYSIS { + const auto display = getDefaultDisplayDeviceLocked(); + if (!display || mBootStage != BootStage::FINISHED) { return; } // TODO(b/113612090): There should be a message queue flush here. Because this esentially @@ -1458,8 +1468,7 @@ void SurfaceFlinger::setRefreshRateTo(float newFps) { // refresh cycle. // Don't do any updating if the current fps is the same as the new one. - const auto activeConfig = getHwComposer().getActiveConfig(*displayId); - const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod(); + const nsecs_t currentVsyncPeriod = getVsyncPeriod(); if (currentVsyncPeriod == 0) { return; } @@ -1470,7 +1479,7 @@ void SurfaceFlinger::setRefreshRateTo(float newFps) { return; } - auto configs = getHwComposer().getConfigs(*displayId); + auto configs = getHwComposer().getConfigs(*display->getId()); for (int i = 0; i < configs.size(); i++) { const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod(); if (vsyncPeriod == 0) { @@ -1480,11 +1489,12 @@ void SurfaceFlinger::setRefreshRateTo(float newFps) { // TODO(b/113612090): There should be a better way at determining which config // has the right refresh rate. if (std::abs(fps - newFps) <= 1) { - const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY); - if (!display) return; + const sp token = display->getDisplayToken().promote(); + LOG_ALWAYS_FATAL_IF(token == nullptr); + // This is posted in async function to avoid deadlock when getDisplayDevice // requires mStateLock. - setActiveConfigAsync(display, i); + setActiveConfigAsync(token, i); ATRACE_INT("FPS", newFps); } } @@ -1524,10 +1534,10 @@ void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDispl repaintEverythingForHWC(); } -void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) { +void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) { ATRACE_CALL(); Mutex::Autolock lock(mStateLock); - if (const auto displayId = getInternalDisplayId()) { + if (const auto displayId = getInternalDisplayIdLocked()) { getHwComposer().setVsyncEnabled(*displayId, enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable); } @@ -2593,14 +2603,13 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mPendingHotplugEvents.clear(); } -void SurfaceFlinger::dispatchDisplayHotplugEvent(EventThread::DisplayType displayType, - bool connected) { +void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) { if (mUseScheduler) { - mScheduler->hotplugReceived(mAppConnectionHandle, displayType, connected); - mScheduler->hotplugReceived(mSfConnectionHandle, displayType, connected); + mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected); + mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected); } else { - mEventThread->onHotplugReceived(displayType, connected); - mSFEventThread->onHotplugReceived(displayType, connected); + mEventThread->onHotplugReceived(displayId, connected); + mSFEventThread->onHotplugReceived(displayId, connected); } } @@ -2616,7 +2625,7 @@ sp SurfaceFlinger::setupNewDisplayDeviceInternal( creationArgs.hasWideColorGamut = false; creationArgs.supportedPerFrameMetadata = 0; - const bool isInternalDisplay = displayId && displayId == getInternalDisplayId(); + const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked(); creationArgs.isPrimary = isInternalDisplay; if (useColorManagement && displayId) { @@ -2699,19 +2708,18 @@ void SurfaceFlinger::processDisplayChangesLocked() { for (size_t i = 0; i < dc;) { const ssize_t j = curr.indexOfKey(draw.keyAt(i)); if (j < 0) { - // Save display IDs before disconnecting. - const auto internalDisplayId = getInternalDisplayId(); - const auto externalDisplayId = getExternalDisplayId(); - // in drawing state but not in current state if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) { + // Save display ID before disconnecting. + const auto displayId = display->getId(); display->disconnect(); + + if (!display->isVirtual()) { + LOG_ALWAYS_FATAL_IF(!displayId); + dispatchDisplayHotplugEvent(displayId->value, false); + } } - if (internalDisplayId && internalDisplayId == draw[i].displayId) { - dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, false); - } else if (externalDisplayId && externalDisplayId == draw[i].displayId) { - dispatchDisplayHotplugEvent(EventThread::DisplayType::External, false); - } + mDisplays.erase(draw.keyAt(i)); } else { // this display is in both lists. see if something changed. @@ -2814,12 +2822,7 @@ void SurfaceFlinger::processDisplayChangesLocked() { dispSurface, producer)); if (!state.isVirtual()) { LOG_ALWAYS_FATAL_IF(!displayId); - - if (displayId == getInternalDisplayId()) { - dispatchDisplayHotplugEvent(EventThread::DisplayType::Primary, true); - } else if (displayId == getExternalDisplayId()) { - dispatchDisplayHotplugEvent(EventThread::DisplayType::External, true); - } + dispatchDisplayHotplugEvent(displayId->value, true); } } } @@ -4829,7 +4832,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co " gpu_to_cpu_unsupported : %d\n", mTransactionFlags.load(), !mGpuToCpuSupported); - if (const auto displayId = getInternalDisplayId(); + if (const auto displayId = getInternalDisplayIdLocked(); displayId && getHwComposer().isConnected(*displayId)) { const auto activeConfig = getHwComposer().getActiveConfig(*displayId); StringAppendF(&result, @@ -4999,7 +5002,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { // information, so it is OK to pass them. case AUTHENTICATE_SURFACE: case GET_ACTIVE_CONFIG: - case GET_BUILT_IN_DISPLAY: + case GET_PHYSICAL_DISPLAY_IDS: + case GET_PHYSICAL_DISPLAY_TOKEN: case GET_DISPLAY_COLOR_MODES: case GET_DISPLAY_NATIVE_PRIMARIES: case GET_DISPLAY_CONFIGS: diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a48e8113d3..73b0cde413 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -313,7 +313,7 @@ public: compositionengine::CompositionEngine& getCompositionEngine() const; // returns the default Display - sp getDefaultDisplayDevice() const { + sp getDefaultDisplayDevice() { Mutex::Autolock _l(mStateLock); return getDefaultDisplayDeviceLocked(); } @@ -327,7 +327,7 @@ public: // enable/disable h/w composer event // TODO: this should be made accessible only to EventThread - void setVsyncEnabled(EventThread::DisplayType displayType, bool enabled); + void setPrimaryVsyncEnabled(bool enabled); // called on the main thread by MessageQueue when an internal message // is received @@ -414,7 +414,8 @@ private: sp createConnection() override; sp createDisplay(const String8& displayName, bool secure) override; void destroyDisplay(const sp& displayToken) override; - sp getBuiltInDisplay(int32_t id) override; + std::vector getPhysicalDisplayIds() const override; + sp getPhysicalDisplayToken(PhysicalDisplayId displayId) const override; void setTransactionState(const Vector& state, const Vector& displays, uint32_t flags, const sp& applyToken, @@ -657,7 +658,7 @@ private: } sp getDefaultDisplayDeviceLocked() { - if (const auto token = getInternalDisplayToken()) { + if (const auto token = getInternalDisplayTokenLocked()) { return getDisplayDeviceLocked(token); } return nullptr; @@ -761,7 +762,7 @@ private: void processDisplayChangesLocked(); void processDisplayHotplugEventsLocked(); - void dispatchDisplayHotplugEvent(EventThread::DisplayType displayType, bool connected); + void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected); /* ------------------------------------------------------------------------ * VSync @@ -801,12 +802,12 @@ private: /* * Display identification */ - sp getPhysicalDisplayToken(DisplayId displayId) const { + sp getPhysicalDisplayTokenLocked(DisplayId displayId) const { const auto it = mPhysicalDisplayTokens.find(displayId); return it != mPhysicalDisplayTokens.end() ? it->second : nullptr; } - std::optional getPhysicalDisplayId(const sp& displayToken) const { + std::optional getPhysicalDisplayIdLocked(const sp& displayToken) const { for (const auto& [id, token] : mPhysicalDisplayTokens) { if (token == displayToken) { return id; @@ -816,22 +817,16 @@ private: } // TODO(b/74619554): Remove special cases for primary display. - sp getInternalDisplayToken() const { - const auto displayId = getInternalDisplayId(); - return displayId ? getPhysicalDisplayToken(*displayId) : nullptr; + sp getInternalDisplayTokenLocked() const { + const auto displayId = getInternalDisplayIdLocked(); + return displayId ? getPhysicalDisplayTokenLocked(*displayId) : nullptr; } - std::optional getInternalDisplayId() const { + std::optional getInternalDisplayIdLocked() const { const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId(); return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; } - // TODO(b/74619554): Remove special cases for external display. - std::optional getExternalDisplayId() const { - const auto hwcDisplayId = getHwComposer().getExternalHwcDisplayId(); - return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt; - } - /* * Debugging & dumpsys */ @@ -951,7 +946,6 @@ private: std::unique_ptr mSfEventThreadSource; std::unique_ptr mVSyncInjector; std::unique_ptr mEventControlThread; - std::unordered_map> mPhysicalDisplayTokens; // Calculates correct offsets. VSyncModulator mVsyncModulator; @@ -985,6 +979,7 @@ private: // this may only be written from the main thread with mStateLock held // it may be read from other threads with mStateLock held std::map, sp> mDisplays; + std::unordered_map> mPhysicalDisplayTokens; // don't use a lock for these, we don't care int mDebugRegion; diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index f021d3dfa7..61d09daed2 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -62,9 +62,11 @@ protected: } void setupBackgroundSurface() { - mDisplay = SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); + mDisplay = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(mDisplay == nullptr); + DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(mDisplay, &info); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info)); const ssize_t displayWidth = info.w; const ssize_t displayHeight = info.h; @@ -170,10 +172,8 @@ TEST_F(CredentialsTest, ClientInitTest) { } TEST_F(CredentialsTest, GetBuiltInDisplayAccessTest) { - std::function condition = [=]() { - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); - return (display != nullptr); + std::function condition = [] { + return SurfaceComposerClient::getInternalDisplayToken() != nullptr; }; // Anyone can access display information. ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, true)); @@ -183,7 +183,7 @@ TEST_F(CredentialsTest, AllowedGetterMethodsTest) { // The following methods are tested with a UID that is not root, graphics, // or system, to show that anyone can access them. setBinUID(); - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); ASSERT_TRUE(display != nullptr); DisplayInfo info; @@ -199,7 +199,7 @@ TEST_F(CredentialsTest, AllowedGetterMethodsTest) { } TEST_F(CredentialsTest, GetDisplayColorModesTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { Vector outColorModes; return SurfaceComposerClient::getDisplayColorModes(display, &outColorModes); @@ -208,7 +208,7 @@ TEST_F(CredentialsTest, GetDisplayColorModesTest) { } TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { ui::DisplayPrimaries primaries; return SurfaceComposerClient::getDisplayNativePrimaries(display, primaries); @@ -217,7 +217,7 @@ TEST_F(CredentialsTest, GetDisplayNativePrimariesTest) { } TEST_F(CredentialsTest, SetActiveConfigTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { return SurfaceComposerClient::setActiveConfig(display, 0); }; @@ -225,7 +225,7 @@ TEST_F(CredentialsTest, SetActiveConfigTest) { } TEST_F(CredentialsTest, SetActiveColorModeTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { return SurfaceComposerClient::setActiveColorMode(display, ui::ColorMode::NATIVE); }; @@ -258,7 +258,7 @@ TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) { } TEST_F(CredentialsTest, CaptureTest) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); std::function condition = [=]() { sp outBuffer; return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB, @@ -324,7 +324,8 @@ TEST_F(CredentialsTest, GetLayerDebugInfo) { } TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); bool result = false; status_t error = SurfaceComposerClient::isWideColorDisplay(display, &result); ASSERT_EQ(NO_ERROR, error); @@ -346,7 +347,8 @@ TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { } TEST_F(CredentialsTest, IsWideColorDisplayWithPrivileges) { - sp display(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); std::function condition = [=]() { bool result = false; return SurfaceComposerClient::isWideColorDisplay(display, &result); diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp index 8ec3e154e3..5cc946aa79 100644 --- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp +++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp @@ -240,10 +240,12 @@ void SurfaceInterceptorTest::capture(TestAction action, Trace* outTrace) { } void SurfaceInterceptorTest::setupBackgroundSurface() { - sp display(SurfaceComposerClient::getBuiltInDisplay( - ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info)); + ssize_t displayWidth = info.w; ssize_t displayHeight = info.h; diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 56d3bd49a8..05a73dcd94 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -195,13 +195,12 @@ static void fillSurfaceRGBA8(const sp& sc, uint8_t r, uint8_t g, class ScreenCapture : public RefBase { public: static void captureScreen(std::unique_ptr* sc) { - sp sf(ComposerService::getComposerService()); - sp display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto sf = ComposerService::getComposerService(); + const auto token = sf->getInternalDisplayToken(); SurfaceComposerClient::Transaction().apply(true); sp outBuffer; - ASSERT_EQ(NO_ERROR, - sf->captureScreen(display, &outBuffer, Rect(), 0, 0, false)); + ASSERT_EQ(NO_ERROR, sf->captureScreen(token, &outBuffer, Rect(), 0, 0, false)); *sc = std::make_unique(outBuffer); } @@ -324,7 +323,6 @@ protected: ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); sp sf(ComposerService::getComposerService()); - sp binder = sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed)); } @@ -502,12 +500,12 @@ protected: private: void SetUpDisplay() { - mDisplay = mClient->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); - ASSERT_NE(nullptr, mDisplay.get()) << "failed to get built-in display"; + mDisplay = mClient->getInternalDisplayToken(); + ASSERT_FALSE(mDisplay == nullptr) << "failed to get display"; // get display width/height DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(mDisplay, &info); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info)); mDisplayWidth = info.w; mDisplayHeight = info.h; mDisplayRect = @@ -558,8 +556,7 @@ public: return mDelegate->screenshot(); case RenderPath::VIRTUAL_DISPLAY: - sp mainDisplay = - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain); + const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken(); DisplayInfo mainDisplayInfo; SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo); @@ -3930,10 +3927,11 @@ protected: LayerTransactionTest::SetUp(); ASSERT_EQ(NO_ERROR, mClient->initCheck()); - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info)); ssize_t displayWidth = info.w; ssize_t displayHeight = info.h; diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index 16e08918a0..f9e0b6413b 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -145,7 +145,7 @@ protected: void TearDown() override; void waitForDisplayTransaction(); - bool waitForHotplugEvent(uint32_t id, bool connected); + bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected); sp mFakeService; sp mComposerClient; @@ -242,7 +242,7 @@ void DisplayTest::waitForDisplayTransaction() { mMockComposer->runVSyncAndWait(); } -bool DisplayTest::waitForHotplugEvent(uint32_t id, bool connected) { +bool DisplayTest::waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) { int waitCount = 20; while (waitCount--) { while (!mReceivedDisplayEvents.empty()) { @@ -250,11 +250,12 @@ bool DisplayTest::waitForHotplugEvent(uint32_t id, bool connected) { mReceivedDisplayEvents.pop_front(); ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, - "event hotplug: id %d, connected %d\t", event.header.id, - event.hotplug.connected); + "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT + ", connected %d\t", + event.header.displayId, event.hotplug.connected); if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG && - event.header.id == id && event.hotplug.connected == connected) { + event.header.displayId == displayId && event.hotplug.connected == connected) { return true; } } @@ -294,13 +295,14 @@ TEST_F(DisplayTest, Hotplug) { waitForDisplayTransaction(); - EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true)); + EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true)); { - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY); + ASSERT_FALSE(display == nullptr); + DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info)); ASSERT_EQ(400u, info.w); ASSERT_EQ(200u, info.h); @@ -328,14 +330,15 @@ TEST_F(DisplayTest, Hotplug) { waitForDisplayTransaction(); - EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, false)); - EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdHdmi, true)); + EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false)); + EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true)); { - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdHdmi)); + const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY); + ASSERT_FALSE(display == nullptr); + DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info)); ASSERT_EQ(400u, info.w); ASSERT_EQ(200u, info.h); @@ -364,11 +367,12 @@ TEST_F(DisplayTest, HotplugPrimaryDisplay) { waitForDisplayTransaction(); - EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, false)); + EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false)); { - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY); + EXPECT_FALSE(display == nullptr); + DisplayInfo info; auto result = SurfaceComposerClient::getDisplayInfo(display, &info); EXPECT_NE(NO_ERROR, result); @@ -402,11 +406,12 @@ TEST_F(DisplayTest, HotplugPrimaryDisplay) { waitForDisplayTransaction(); - EXPECT_TRUE(waitForHotplugEvent(ISurfaceComposer::eDisplayIdMain, true)); + EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true)); { - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY); + EXPECT_FALSE(display == nullptr); + DisplayInfo info; auto result = SurfaceComposerClient::getDisplayInfo(display, &info); EXPECT_EQ(NO_ERROR, result); @@ -473,10 +478,11 @@ void TransactionTest::SetUp() { ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); ALOGI("TransactionTest::SetUp - display"); - sp display( - SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain)); + const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY); + ASSERT_FALSE(display == nullptr); + DisplayInfo info; - SurfaceComposerClient::getDisplayInfo(display, &info); + ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info)); mDisplayWidth = info.w; mDisplayHeight = info.h; diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 4cb79ab495..da3472e3fa 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -45,9 +45,9 @@ namespace android { namespace { using testing::_; -using testing::ByMove; using testing::DoAll; using testing::Mock; +using testing::ResultOf; using testing::Return; using testing::SetArgPointee; @@ -321,11 +321,6 @@ struct DisplayVariant { // Whether the display is primary static constexpr Primary PRIMARY = primary; - static constexpr auto displayType() { - return static_cast(PRIMARY) ? EventThread::DisplayType::Primary - : EventThread::DisplayType::External; - } - static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) { auto injector = FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(), @@ -1470,6 +1465,9 @@ public: template void setupCommonPreconditions(); + template + static void expectHotplugReceived(mock::EventThread*); + template void setupCommonCallExpectationsForConnectProcessing(); @@ -1507,6 +1505,17 @@ void HandleTransactionLockedTest::setupCommonPreconditions() { injectFakeNativeWindowSurfaceFactory(); } +template +void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) { + const auto convert = [](auto physicalDisplayId) { + return std::make_optional(DisplayId{physicalDisplayId}); + }; + + EXPECT_CALL(*eventThread, + onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected)) + .Times(1); +} + template void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() { Case::Display::setupHwcHotplugCallExpectations(this); @@ -1522,16 +1531,16 @@ void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessin EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1); - EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1); - EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), true)).Times(1); + expectHotplugReceived(mEventThread); + expectHotplugReceived(mSFEventThread); } template void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() { EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1); - EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1); - EXPECT_CALL(*mSFEventThread, onHotplugReceived(Case::Display::displayType(), false)).Times(1); + expectHotplugReceived(mEventThread); + expectHotplugReceived(mSFEventThread); } template diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index dd90063d93..ad7dcb4217 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -36,6 +36,9 @@ using testing::Invoke; namespace android { namespace { +constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111; +constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = 222; + class MockVSyncSource : public VSyncSource { public: MOCK_METHOD1(setVSyncEnabled, void(bool)); @@ -72,7 +75,7 @@ protected: ConnectionEventRecorder& connectionEventRecorder, nsecs_t expectedTimestamp, unsigned expectedCount); void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount); - void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType, + void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, bool expectedConnected); AsyncCallRecorder mVSyncSetEnabledCallRecorder; @@ -106,8 +109,8 @@ EventThreadTest::EventThreadTest() { mConnection = createConnection(mConnectionEventCallRecorder); // A display must be connected for VSYNC events to be delivered. - mThread->onHotplugReceived(EventThread::DisplayType::Primary, true); - expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true); + mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true); + expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true); } EventThreadTest::~EventThreadTest() { @@ -183,16 +186,13 @@ void EventThreadTest::expectVsyncEventReceivedByConnection(nsecs_t expectedTimes expectedCount); } -void EventThreadTest::expectHotplugEventReceivedByConnection( - EventThread::DisplayType expectedDisplayType, bool expectedConnected) { - const uint32_t expectedDisplayId = - expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1; - +void EventThreadTest::expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId, + bool expectedConnected) { auto args = mConnectionEventCallRecorder.waitForCall(); ASSERT_TRUE(args.has_value()); const auto& event = std::get<0>(args.value()); EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type); - EXPECT_EQ(expectedDisplayId, event.header.id); + EXPECT_EQ(expectedDisplayId, event.header.displayId); EXPECT_EQ(expectedConnected, event.hotplug.connected); } @@ -212,8 +212,8 @@ TEST_F(EventThreadTest, canCreateAndDestroyThreadWithNoEventsSent) { } TEST_F(EventThreadTest, vsyncRequestIsIgnoredIfDisplayIsDisconnected) { - mThread->onHotplugReceived(EventThread::DisplayType::Primary, false); - expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false); + mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false); + expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false); // Signal that we want the next vsync event to be posted to the connection. mThread->requestNextVsync(mConnection, false); @@ -400,24 +400,24 @@ TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) { expectVSyncSetPhaseOffsetCallReceived(321); } -TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) { - mThread->onHotplugReceived(EventThread::DisplayType::Primary, false); - expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false); +TEST_F(EventThreadTest, postHotplugInternalDisconnect) { + mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false); + expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false); } -TEST_F(EventThreadTest, postHotplugPrimaryConnect) { - mThread->onHotplugReceived(EventThread::DisplayType::Primary, true); - expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true); +TEST_F(EventThreadTest, postHotplugInternalConnect) { + mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true); + expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, true); } TEST_F(EventThreadTest, postHotplugExternalDisconnect) { - mThread->onHotplugReceived(EventThread::DisplayType::External, false); - expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false); + mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, false); + expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, false); } TEST_F(EventThreadTest, postHotplugExternalConnect) { - mThread->onHotplugReceived(EventThread::DisplayType::External, true); - expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true); + mThread->onHotplugReceived(EXTERNAL_DISPLAY_ID, true); + expectHotplugEventReceivedByConnection(EXTERNAL_DISPLAY_ID, true); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 4d9aec6b66..0db96d95ce 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -18,6 +18,8 @@ using testing::Return; namespace android { +constexpr PhysicalDisplayId PHYSICAL_DISPLAY_ID = 999; + class SchedulerTest : public testing::Test { protected: class MockEventThreadConnection : public android::EventThreadConnection { @@ -104,8 +106,7 @@ TEST_F(SchedulerTest, testNullPtr) { EXPECT_TRUE(returnedValue == nullptr); EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr); EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr); - ASSERT_NO_FATAL_FAILURE( - mScheduler->hotplugReceived(nullptr, EventThread::DisplayType::Primary, false)); + ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false)); ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr)); ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr)); std::string testString; @@ -129,8 +130,8 @@ TEST_F(SchedulerTest, invalidConnectionHandle) { // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads. EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0); - ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(connectionHandle, - EventThread::DisplayType::Primary, false)); + ASSERT_NO_FATAL_FAILURE( + mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false)); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0); ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle)); @@ -158,10 +159,9 @@ TEST_F(SchedulerTest, validConnectionHandle) { EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr); EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr); - EXPECT_CALL(*mEventThread, onHotplugReceived(EventThread::DisplayType::Primary, false)) - .Times(1); - ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(mConnectionHandle, - EventThread::DisplayType::Primary, false)); + EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1); + ASSERT_NO_FATAL_FAILURE( + mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false)); EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1); ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index 3242ef12a4..aaf67e9559 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -31,7 +31,7 @@ public: MOCK_CONST_METHOD1(createEventConnection, sp(ResyncCallback)); MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); - MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool)); + MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); MOCK_CONST_METHOD1(dump, void(std::string&)); MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset)); MOCK_METHOD1(registerDisplayEventConnection, -- cgit v1.2.3-59-g8ed1b From 734116201d021cccd1d446fe8300f995a0019e42 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 25 Jan 2019 10:45:41 -0800 Subject: blast: implicitly cache buffers Sending buffers between processes is expensive so they must be cached. Currently buffers are explictly cached. This patch updates them to implicitly cache them per client process. The max buffers per process is 64. After that, the cache will try to evict buffers that have been destroyed. If it doesn't find any, it will evict the least recently used buffer. Test: Transaction_test Bug: 80477568 Change-Id: Id048d32e05e19d0ce875212cbcddf997736110fd --- libs/gui/ISurfaceComposer.cpp | 78 ------- libs/gui/SurfaceComposerClient.cpp | 149 ++++++++++--- libs/gui/include/gui/ISurfaceComposer.h | 7 - libs/gui/include/gui/SurfaceComposerClient.h | 6 - libs/gui/tests/Surface_test.cpp | 5 - services/surfaceflinger/BufferStateLayerCache.cpp | 95 ++++---- services/surfaceflinger/BufferStateLayerCache.h | 34 +-- services/surfaceflinger/SurfaceFlinger.cpp | 28 +-- services/surfaceflinger/SurfaceFlinger.h | 5 - services/surfaceflinger/tests/Transaction_test.cpp | 248 +++++++++------------ 10 files changed, 302 insertions(+), 353 deletions(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index bef68ef22f..fd30e3b998 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -722,42 +722,6 @@ public: return error; } - virtual status_t cacheBuffer(const sp& token, const sp& buffer, - int32_t* outBufferId) { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - - data.writeStrongBinder(token); - if (buffer) { - data.writeBool(true); - data.write(*buffer); - } else { - data.writeBool(false); - } - - status_t result = remote()->transact(BnSurfaceComposer::CACHE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - - int32_t id = -1; - result = reply.readInt32(&id); - if (result == NO_ERROR) { - *outBufferId = id; - } - return result; - } - - virtual status_t uncacheBuffer(const sp& token, int32_t bufferId) { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - - data.writeStrongBinder(token); - data.writeInt32(bufferId); - - return remote()->transact(BnSurfaceComposer::UNCACHE_BUFFER, data, &reply); - } - virtual status_t isWideColorDisplay(const sp& token, bool* outIsWideColorDisplay) const { Parcel data, reply; @@ -1238,48 +1202,6 @@ status_t BnSurfaceComposer::onTransact( } return error; } - case CACHE_BUFFER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp token; - status_t result = data.readStrongBinder(&token); - if (result != NO_ERROR) { - ALOGE("cache buffer failure in reading token: %d", result); - return result; - } - - sp buffer = new GraphicBuffer(); - if (data.readBool()) { - result = data.read(*buffer); - if (result != NO_ERROR) { - ALOGE("cache buffer failure in reading buffer: %d", result); - return result; - } - } - int32_t bufferId = -1; - status_t error = cacheBuffer(token, buffer, &bufferId); - if (error == NO_ERROR) { - reply->writeInt32(bufferId); - } - return error; - } - case UNCACHE_BUFFER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp token; - status_t result = data.readStrongBinder(&token); - if (result != NO_ERROR) { - ALOGE("uncache buffer failure in reading token: %d", result); - return result; - } - - int32_t bufferId = -1; - result = data.readInt32(&bufferId); - if (result != NO_ERROR) { - ALOGE("uncache buffer failure in reading buffer id: %d", result); - return result; - } - - return uncacheBuffer(token, bufferId); - } case IS_WIDE_COLOR_DISPLAY: { CHECK_INTERFACE(ISurfaceComposer, data, reply); sp display = nullptr; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c712bde97d..da624cc755 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -48,6 +48,9 @@ #include +// This server size should always be smaller than the server cache size +#define BUFFER_CACHE_MAX_SIZE 64 + namespace android { using ui::ColorMode; @@ -230,6 +233,113 @@ void TransactionCompletedListener::onTransactionCompleted(ListenerStats listener // --------------------------------------------------------------------------- +class BufferCache : public Singleton { +public: + BufferCache() : token(new BBinder()) {} + + sp getToken() { + return IInterface::asBinder(TransactionCompletedListener::getIInstance()); + } + + int32_t getId(const sp& buffer) { + std::lock_guard lock(mMutex); + + auto itr = mBuffers.find(buffer); + if (itr == mBuffers.end()) { + return -1; + } + itr->second.counter = getCounter(); + return itr->second.id; + } + + int32_t cache(const sp& buffer) { + std::lock_guard lock(mMutex); + + int32_t bufferId = getNextAvailableId(); + + mBuffers[buffer].id = bufferId; + mBuffers[buffer].counter = getCounter(); + return bufferId; + } + +private: + int32_t evictDestroyedBuffer() REQUIRES(mMutex) { + auto itr = mBuffers.begin(); + while (itr != mBuffers.end()) { + auto& buffer = itr->first; + if (buffer == nullptr || buffer.promote() == nullptr) { + int32_t bufferId = itr->second.id; + mBuffers.erase(itr); + return bufferId; + } + itr++; + } + return -1; + } + + int32_t evictLeastRecentlyUsedBuffer() REQUIRES(mMutex) { + if (mBuffers.size() < 0) { + return -1; + } + auto itr = mBuffers.begin(); + uint64_t minCounter = itr->second.counter; + auto minBuffer = itr; + itr++; + + while (itr != mBuffers.end()) { + uint64_t counter = itr->second.counter; + if (counter < minCounter) { + minCounter = counter; + minBuffer = itr; + } + itr++; + } + int32_t minBufferId = minBuffer->second.id; + mBuffers.erase(minBuffer); + return minBufferId; + } + + int32_t getNextAvailableId() REQUIRES(mMutex) { + static int32_t id = 0; + if (id + 1 < BUFFER_CACHE_MAX_SIZE) { + return id++; + } + + // There are no more valid cache ids. To set additional buffers, evict existing buffers + // and reuse their cache ids. + int32_t bufferId = evictDestroyedBuffer(); + if (bufferId > 0) { + return bufferId; + } + return evictLeastRecentlyUsedBuffer(); + } + + uint64_t getCounter() REQUIRES(mMutex) { + static uint64_t counter = 0; + return counter++; + } + + struct Metadata { + // The cache id of a buffer that can be set to ISurfaceComposer. When ISurfaceComposer + // recieves this id, it can retrieve the buffer from its cache. Caching GraphicBuffers + // is important because sending them across processes is expensive. + int32_t id = 0; + // When a buffer is set, a counter is incremented and stored in the cache's metadata. + // When an buffer must be evicted, the entry with the lowest counter value is chosen. + uint64_t counter = 0; + }; + + std::mutex mMutex; + std::map, Metadata> mBuffers GUARDED_BY(mMutex); + + // Used by ISurfaceComposer to identify which process is sending the cached buffer. + sp token; +}; + +ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache); + +// --------------------------------------------------------------------------- + SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : mForceSynchronous(other.mForceSynchronous), mTransactionNestCount(other.mTransactionNestCount), @@ -772,22 +882,17 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe mStatus = BAD_INDEX; return *this; } - s->what |= layer_state_t::eBufferChanged; - s->buffer = buffer; - registerSurfaceControlForCallback(sc); - return *this; -} + int32_t bufferId = BufferCache::getInstance().getId(buffer); + if (bufferId < 0) { + bufferId = BufferCache::getInstance().cache(buffer); -SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachedBuffer( - const sp& sc, int32_t bufferId) { - layer_state_t* s = getLayerState(sc); - if (!s) { - mStatus = BAD_INDEX; - return *this; + s->what |= layer_state_t::eBufferChanged; + s->buffer = buffer; } + s->what |= layer_state_t::eCachedBufferChanged; - s->cachedBuffer.token = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + s->cachedBuffer.token = BufferCache::getInstance().getToken(); s->cachedBuffer.bufferId = bufferId; registerSurfaceControlForCallback(sc); @@ -1230,26 +1335,6 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp& token, // ---------------------------------------------------------------------------- -status_t SurfaceComposerClient::cacheBuffer(const sp& buffer, int32_t* outBufferId) { - sp sf(ComposerService::getComposerService()); - if (buffer == nullptr || outBufferId == nullptr) { - return BAD_VALUE; - } - return sf->cacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()), - buffer, outBufferId); -} - -status_t SurfaceComposerClient::uncacheBuffer(int32_t bufferId) { - sp sf(ComposerService::getComposerService()); - if (bufferId < 0) { - return BAD_VALUE; - } - return sf->uncacheBuffer(IInterface::asBinder(TransactionCompletedListener::getIInstance()), - bufferId); -} - -// ---------------------------------------------------------------------------- - status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { sp sf(ComposerService::getComposerService()); return sf->enableVSyncInjections(enable); diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 3899f6a3d0..7146b7dc17 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -320,11 +320,6 @@ public: */ virtual status_t getProtectedContentSupport(bool* outSupported) const = 0; - virtual status_t cacheBuffer(const sp& token, const sp& buffer, - int32_t* outBufferId) = 0; - - virtual status_t uncacheBuffer(const sp& token, int32_t bufferId) = 0; - /* * Queries whether the given display is a wide color display. * Requires the ACCESS_SURFACE_FLINGER permission. @@ -373,8 +368,6 @@ public: SET_DISPLAY_CONTENT_SAMPLING_ENABLED, GET_DISPLAYED_CONTENT_SAMPLE, GET_PROTECTED_CONTENT_SUPPORT, - CACHE_BUFFER, - UNCACHE_BUFFER, IS_WIDE_COLOR_DISPLAY, GET_DISPLAY_NATIVE_PRIMARIES, // Always append new enum to the end. diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 8e2bb2b6e6..28e04ca634 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -152,12 +152,6 @@ public: static void doDropReferenceTransaction(const sp& handle, const sp& client); - // Caches a buffer with the ISurfaceComposer so the buffer does not need to be resent across - // processes - static status_t cacheBuffer(const sp& buffer, int32_t* outBufferId); - // Uncaches a buffer set by cacheBuffer - static status_t uncacheBuffer(int32_t bufferId); - // Queries whether a given display is wide color display. static status_t isWideColorDisplay(const sp& display, bool* outIsWideColorDisplay); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 1705fd7383..8bd589d1e7 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -664,11 +664,6 @@ public: status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; } status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; } - status_t cacheBuffer(const sp& /*token*/, const sp& /*buffer*/, - int32_t* /*outBufferId*/) { - return NO_ERROR; - } - status_t uncacheBuffer(const sp& /*token*/, int32_t /*bufferId*/) { return NO_ERROR; } status_t isWideColorDisplay(const sp&, bool*) const override { return NO_ERROR; } protected: diff --git a/services/surfaceflinger/BufferStateLayerCache.cpp b/services/surfaceflinger/BufferStateLayerCache.cpp index c82ad7bc49..cb02d16007 100644 --- a/services/surfaceflinger/BufferStateLayerCache.cpp +++ b/services/surfaceflinger/BufferStateLayerCache.cpp @@ -19,81 +19,84 @@ #define LOG_TAG "BufferStateLayerCache" #define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include + #include "BufferStateLayerCache.h" -#define MAX_CACHE_SIZE 64 +#define VALID_CACHE_ID(id) ((id) >= 0 || (id) < (BUFFER_CACHE_MAX_SIZE)) namespace android { -int32_t BufferStateLayerCache::add(const sp& processToken, - const sp& buffer) { - std::lock_guard lock(mMutex); +ANDROID_SINGLETON_STATIC_INSTANCE(BufferStateLayerCache); - auto& processCache = getProccessCache(processToken); +BufferStateLayerCache::BufferStateLayerCache() : mDeathRecipient(new CacheDeathRecipient) {} - int32_t slot = findSlot(processCache); - if (slot < 0) { - return slot; +void BufferStateLayerCache::add(sp processToken, int32_t id, + const sp& buffer) { + if (!VALID_CACHE_ID(id)) { + ALOGE("failed to cache buffer: invalid buffer id"); + return; } - processCache[slot] = buffer; - - return slot; -} + if (!processToken) { + ALOGE("failed to cache buffer: invalid process token"); + return; + } -void BufferStateLayerCache::release(const sp& processToken, int32_t id) { - if (id < 0) { - ALOGE("invalid buffer id"); + if (!buffer) { + ALOGE("failed to cache buffer: invalid buffer"); return; } std::lock_guard lock(mMutex); - auto& processCache = getProccessCache(processToken); - if (id >= processCache.size()) { - ALOGE("invalid buffer id"); - return; + // If this is a new process token, set a death recipient. If the client process dies, we will + // get a callback through binderDied. + if (mBuffers.find(processToken) == mBuffers.end()) { + status_t err = processToken->linkToDeath(mDeathRecipient); + if (err != NO_ERROR) { + ALOGE("failed to cache buffer: could not link to death"); + return; + } } - processCache[id] = nullptr; + + auto& processBuffers = mBuffers[processToken]; + processBuffers[id] = buffer; } -sp BufferStateLayerCache::get(const sp& processToken, int32_t id) { - if (id < 0) { - ALOGE("invalid buffer id"); +sp BufferStateLayerCache::get(sp processToken, int32_t id) { + if (!VALID_CACHE_ID(id)) { + ALOGE("failed to get buffer: invalid buffer id"); + return nullptr; + } + + if (!processToken) { + ALOGE("failed to cache buffer: invalid process token"); return nullptr; } std::lock_guard lock(mMutex); - auto& processCache = getProccessCache(processToken); + auto itr = mBuffers.find(processToken); + if (itr == mBuffers.end()) { + ALOGE("failed to get buffer: process token not found"); + return nullptr; + } - if (id >= processCache.size()) { - ALOGE("invalid buffer id"); + if (id >= itr->second.size()) { + ALOGE("failed to get buffer: id outside the bounds of the cache"); return nullptr; } - return processCache[id]; -} -std::vector>& BufferStateLayerCache::getProccessCache( - const sp& processToken) { - return mBuffers[processToken]; + return itr->second[id]; } -int32_t BufferStateLayerCache::findSlot(std::vector>& processCache) { - int32_t slot = 0; - - for (const sp buffer : processCache) { - if (!buffer) { - return slot; - } - slot++; - } - - if (processCache.size() < MAX_CACHE_SIZE) { - processCache.push_back(nullptr); - return slot; - } +void BufferStateLayerCache::removeProcess(const wp& processToken) { + std::lock_guard lock(mMutex); + mBuffers.erase(processToken); +} - return -1; +void BufferStateLayerCache::CacheDeathRecipient::binderDied(const wp& who) { + BufferStateLayerCache::getInstance().removeProcess(who); } }; // namespace android diff --git a/services/surfaceflinger/BufferStateLayerCache.h b/services/surfaceflinger/BufferStateLayerCache.h index 623f0c65fd..ede3feb1c8 100644 --- a/services/surfaceflinger/BufferStateLayerCache.h +++ b/services/surfaceflinger/BufferStateLayerCache.h @@ -20,36 +20,36 @@ #include #include #include +#include +#include +#include #include -#include -#include + +#define BUFFER_CACHE_MAX_SIZE 64 namespace android { -class BufferStateLayerCache { +class BufferStateLayerCache : public Singleton { public: - int32_t add(const sp& processToken, const sp& buffer); - void release(const sp& processToken, int32_t id); + BufferStateLayerCache(); + + void add(sp processToken, int32_t id, const sp& buffer); + sp get(sp processToken, int32_t id); - sp get(const sp& processToken, int32_t id); + void removeProcess(const wp& processToken); private: std::mutex mMutex; + std::map /*caching process*/, std::array, BUFFER_CACHE_MAX_SIZE>> + mBuffers GUARDED_BY(mMutex); - std::vector>& getProccessCache(const sp& processToken) - REQUIRES(mMutex); - - int32_t findSlot(std::vector>& proccessCache) REQUIRES(mMutex); - - struct IBinderHash { - std::size_t operator()(const sp& strongPointer) const { - return std::hash{}(strongPointer.get()); - } + class CacheDeathRecipient : public IBinder::DeathRecipient { + public: + void binderDied(const wp& who) override; }; - std::unordered_map /*caching process*/, std::vector>, IBinderHash> - mBuffers GUARDED_BY(mMutex); + sp mDeathRecipient; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2cf2cd8a5d..d31c13f031 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1161,20 +1161,6 @@ status_t SurfaceFlinger::getProtectedContentSupport(bool* outSupported) const { return NO_ERROR; } -status_t SurfaceFlinger::cacheBuffer(const sp& token, const sp& buffer, - int32_t* outBufferId) { - if (!outBufferId) { - return BAD_VALUE; - } - *outBufferId = mBufferStateLayerCache.add(token, buffer); - return NO_ERROR; -} - -status_t SurfaceFlinger::uncacheBuffer(const sp& token, int32_t bufferId) { - mBufferStateLayerCache.release(token, bufferId); - return NO_ERROR; -} - status_t SurfaceFlinger::isWideColorDisplay(const sp& displayToken, bool* outIsWideColorDisplay) const { if (!displayToken || !outIsWideColorDisplay) { @@ -3971,9 +3957,6 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState if (what & layer_state_t::eFrameChanged) { if (layer->setFrame(s.frame)) flags |= eTraversalNeeded; } - if (what & layer_state_t::eBufferChanged) { - if (layer->setBuffer(s.buffer)) flags |= eTraversalNeeded; - } if (what & layer_state_t::eAcquireFenceChanged) { if (layer->setAcquireFence(s.acquireFence)) flags |= eTraversalNeeded; } @@ -4010,9 +3993,16 @@ uint32_t SurfaceFlinger::setClientStateLocked(const ComposerState& composerState callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface)); } } + + if (what & layer_state_t::eBufferChanged) { + // Add the new buffer to the cache. This should always come before eCachedBufferChanged. + BufferStateLayerCache::getInstance().add(s.cachedBuffer.token, s.cachedBuffer.bufferId, + s.buffer); + } if (what & layer_state_t::eCachedBufferChanged) { sp buffer = - mBufferStateLayerCache.get(s.cachedBuffer.token, s.cachedBuffer.bufferId); + BufferStateLayerCache::getInstance().get(s.cachedBuffer.token, + s.cachedBuffer.bufferId); if (layer->setBuffer(buffer)) flags |= eTraversalNeeded; } if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; @@ -5012,8 +5002,6 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_COLOR_MANAGEMENT: case GET_COMPOSITION_PREFERENCE: case GET_PROTECTED_CONTENT_SUPPORT: - case CACHE_BUFFER: - case UNCACHE_BUFFER: case IS_WIDE_COLOR_DISPLAY: { return OK; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a48e8113d3..e1fa98fc58 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -467,9 +467,6 @@ private: uint64_t timestamp, DisplayedFrameStats* outStats) const override; status_t getProtectedContentSupport(bool* outSupported) const override; - status_t cacheBuffer(const sp& token, const sp& buffer, - int32_t* outBufferId) override; - status_t uncacheBuffer(const sp& token, int32_t bufferId) override; status_t isWideColorDisplay(const sp& displayToken, bool* outIsWideColorDisplay) const override; @@ -1096,8 +1093,6 @@ private: InputWindowCommands mInputWindowCommands; - BufferStateLayerCache mBufferStateLayerCache; - ui::DisplayPrimaries mInternalDisplayPrimaries; }; }; // namespace android diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index 56d3bd49a8..70d9dab8a1 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -2374,6 +2374,117 @@ TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) { } } +TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) { + sp layer; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + + std::array colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN}; + + std::array, 10> buffers; + + size_t idx = 0; + for (auto& buffer : buffers) { + buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + Color color = colors[idx % colors.size()]; + fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); + idx++; + } + + // Set each buffer twice. The first time adds it to the cache, the second time tests that the + // cache is working. + idx = 0; + for (auto& buffer : buffers) { + for (int i = 0; i < 2; i++) { + Transaction().setBuffer(layer, buffer).apply(); + + Color color = colors[idx % colors.size()]; + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } + idx++; + } +} + +TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) { + sp layer; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + + std::array colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN}; + + std::array, 70> buffers; + + size_t idx = 0; + for (auto& buffer : buffers) { + buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + Color color = colors[idx % colors.size()]; + fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); + idx++; + } + + // Set each buffer twice. The first time adds it to the cache, the second time tests that the + // cache is working. + idx = 0; + for (auto& buffer : buffers) { + for (int i = 0; i < 2; i++) { + Transaction().setBuffer(layer, buffer).apply(); + + Color color = colors[idx % colors.size()]; + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } + idx++; + } +} + +TEST_F(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) { + sp layer; + ASSERT_NO_FATAL_FAILURE( + layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); + + std::array colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN}; + + std::array, 65> buffers; + + size_t idx = 0; + for (auto& buffer : buffers) { + buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY, + "test"); + Color color = colors[idx % colors.size()]; + fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color); + idx++; + } + + // Set each buffer twice. The first time adds it to the cache, the second time tests that the + // cache is working. + idx = 0; + for (auto& buffer : buffers) { + for (int i = 0; i < 2; i++) { + Transaction().setBuffer(layer, buffer).apply(); + + Color color = colors[idx % colors.size()]; + auto shot = screenshot(); + shot->expectColor(Rect(0, 0, 32, 32), color); + shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); + } + if (idx == 0) { + buffers[0].clear(); + } + idx++; + } +} + TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) { sp layer; ASSERT_NO_FATAL_FAILURE( @@ -2657,143 +2768,6 @@ TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) { Transaction().setSidebandStream(layer, nullptr).apply(); } -TEST_F(LayerTransactionTest, CacheBuffer_BufferState) { - sp buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY, - "test"); - - int32_t bufferId = -1; - ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); - ASSERT_GE(bufferId, 0); - - ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); -} - -TEST_F(LayerTransactionTest, CacheBuffers_BufferState) { - std::vector bufferIds; - int32_t bufferCount = 20; - - for (int i = 0; i < bufferCount; i++) { - sp buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY, - "test"); - int32_t bufferId = -1; - ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); - if (bufferId < 0) { - EXPECT_GE(bufferId, 0); - break; - } - bufferIds.push_back(bufferId); - } - - for (int32_t bufferId : bufferIds) { - ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); - } -} - -TEST_F(LayerTransactionTest, CacheBufferInvalid_BufferState) { - sp buffer = nullptr; - - int32_t bufferId = -1; - ASSERT_NE(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); - ASSERT_LT(bufferId, 0); -} - -TEST_F(LayerTransactionTest, UncacheBufferTwice_BufferState) { - sp buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY, - "test"); - - int32_t bufferId = -1; - ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); - ASSERT_GE(bufferId, 0); - - ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); - mClient->uncacheBuffer(bufferId); -} - -TEST_F(LayerTransactionTest, UncacheBufferInvalidId_BufferState) { - mClient->uncacheBuffer(-1); - mClient->uncacheBuffer(0); - mClient->uncacheBuffer(1); - mClient->uncacheBuffer(5); - mClient->uncacheBuffer(1000); -} - -TEST_F(LayerTransactionTest, SetCachedBuffer_BufferState) { - sp layer; - ASSERT_NO_FATAL_FAILURE( - layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - - sp buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY, - "test"); - - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED); - - int32_t bufferId = -1; - ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(buffer, &bufferId)); - ASSERT_GE(bufferId, 0); - - Transaction().setCachedBuffer(layer, bufferId).apply(); - - auto shot = screenshot(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); - - ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); -} - -TEST_F(LayerTransactionTest, SetCachedBufferDelayed_BufferState) { - sp layer; - ASSERT_NO_FATAL_FAILURE( - layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState)); - - sp cachedBuffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY, - "test"); - int32_t bufferId = -1; - ASSERT_EQ(NO_ERROR, mClient->cacheBuffer(cachedBuffer, &bufferId)); - ASSERT_GE(bufferId, 0); - - sp buffer = - new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1, - BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | - BufferUsage::COMPOSER_OVERLAY, - "test"); - fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::BLUE); - Transaction().setBuffer(layer, buffer).apply(); - { - SCOPED_TRACE("Uncached buffer"); - - auto shot = screenshot(); - shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); - } - - fillGraphicBufferColor(cachedBuffer, Rect(0, 0, 32, 32), Color::RED); - Transaction().setCachedBuffer(layer, bufferId).apply(); - { - SCOPED_TRACE("Cached buffer"); - - auto shot = screenshot(); - shot->expectColor(Rect(0, 0, 32, 32), Color::RED); - shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK); - } - - ASSERT_EQ(NO_ERROR, mClient->uncacheBuffer(bufferId)); -} - TEST_F(LayerTransactionTest, ReparentToSelf) { sp layer; ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32)); -- cgit v1.2.3-59-g8ed1b From 84ab93713351453fa70e6acfdedd18f6702ca199 Mon Sep 17 00:00:00 2001 From: Dan Stoza Date: Mon, 17 Dec 2018 15:27:57 -0800 Subject: [gui] Add {add,remove}RegionSamplingListener Adds addRegionSamplingListener and removeRegionSamplingListener to ISurfaceComposer. This interface will allow a client to register to receive an updated median luma value for a region bounded by a stop layer (i.e., layers behind the stop layer) and the provided Rect any time the display updates. Multiple areas may be sampled, but they must use separate listeners, and the layer traversal will stop at the stop layer with the lesser Z value. Bug: 119639245 Test: New test in I152a9d72640e34e4f83959715cdea409929b9150 Change-Id: Ie420098781ddba02d6eb0d7039d0bf855c204231 --- libs/gui/Android.bp | 1 + libs/gui/IRegionSamplingListener.cpp | 64 ++++++++++++++++++++ libs/gui/ISurfaceComposer.cpp | 84 ++++++++++++++++++++++++++ libs/gui/include/gui/IRegionSamplingListener.h | 43 +++++++++++++ libs/gui/include/gui/ISurfaceComposer.h | 23 +++++++ libs/gui/tests/Surface_test.cpp | 10 +++ services/surfaceflinger/SurfaceFlinger.cpp | 15 ++++- services/surfaceflinger/SurfaceFlinger.h | 4 +- 8 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 libs/gui/IRegionSamplingListener.cpp create mode 100644 libs/gui/include/gui/IRegionSamplingListener.h (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index f40eb6c40e..0510492803 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -104,6 +104,7 @@ cc_library_shared { "IGraphicBufferConsumer.cpp", "IGraphicBufferProducer.cpp", "IProducerListener.cpp", + "IRegionSamplingListener.cpp", "ISurfaceComposer.cpp", "ISurfaceComposerClient.cpp", "ITransactionCompletedListener.cpp", diff --git a/libs/gui/IRegionSamplingListener.cpp b/libs/gui/IRegionSamplingListener.cpp new file mode 100644 index 0000000000..40cbfceaf7 --- /dev/null +++ b/libs/gui/IRegionSamplingListener.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "IRegionSamplingListener" +//#define LOG_NDEBUG 0 + +#include + +namespace android { + +namespace { // Anonymous + +enum class Tag : uint32_t { + ON_SAMPLE_COLLECTED = IBinder::FIRST_CALL_TRANSACTION, + LAST = ON_SAMPLE_COLLECTED, +}; + +} // Anonymous namespace + +class BpRegionSamplingListener : public SafeBpInterface { +public: + explicit BpRegionSamplingListener(const sp& impl) + : SafeBpInterface(impl, "BpRegionSamplingListener") {} + + ~BpRegionSamplingListener() override; + + void onSampleCollected(float medianLuma) override { + callRemoteAsync(Tag::ON_SAMPLE_COLLECTED, medianLuma); + } +}; + +// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see +// clang warning -Wweak-vtables) +BpRegionSamplingListener::~BpRegionSamplingListener() = default; + +IMPLEMENT_META_INTERFACE(RegionSamplingListener, "android.gui.IRegionSamplingListener"); + +status_t BnRegionSamplingListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast(Tag::LAST)) { + return BBinder::onTransact(code, data, reply, flags); + } + auto tag = static_cast(code); + switch (tag) { + case Tag::ON_SAMPLE_COLLECTED: + return callLocalAsync(data, reply, &IRegionSamplingListener::onSampleCollected); + } +} + +} // namespace android diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index fc9185d998..f77eeb246c 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -754,6 +755,57 @@ public: error = reply.readBool(outIsWideColorDisplay); return error; } + + virtual status_t addRegionSamplingListener(const Rect& samplingArea, + const sp& stopLayerHandle, + const sp& listener) { + Parcel data, reply; + status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to write interface token"); + return error; + } + error = data.write(samplingArea); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to write sampling area"); + return error; + } + error = data.writeStrongBinder(stopLayerHandle); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to write stop layer handle"); + return error; + } + error = data.writeStrongBinder(IInterface::asBinder(listener)); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to write listener"); + return error; + } + error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to transact"); + } + return error; + } + + virtual status_t removeRegionSamplingListener(const sp& listener) { + Parcel data, reply; + status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to write interface token"); + return error; + } + error = data.writeStrongBinder(IInterface::asBinder(listener)); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to write listener"); + return error; + } + error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data, + &reply); + if (error != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to transact"); + } + return error; + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1233,6 +1285,38 @@ status_t BnSurfaceComposer::onTransact( CHECK_INTERFACE(ISurfaceComposer, data, reply); return reply->writeUint64Vector(getPhysicalDisplayIds()); } + case ADD_REGION_SAMPLING_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + Rect samplingArea; + status_t result = data.read(samplingArea); + if (result != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to read sampling area"); + return result; + } + sp stopLayerHandle; + result = data.readNullableStrongBinder(&stopLayerHandle); + if (result != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to read stop layer handle"); + return result; + } + sp listener; + result = data.readNullableStrongBinder(&listener); + if (result != NO_ERROR) { + ALOGE("addRegionSamplingListener: Failed to read listener"); + return result; + } + return addRegionSamplingListener(samplingArea, stopLayerHandle, listener); + } + case REMOVE_REGION_SAMPLING_LISTENER: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + sp listener; + status_t result = data.readNullableStrongBinder(&listener); + if (result != NO_ERROR) { + ALOGE("removeRegionSamplingListener: Failed to read listener"); + return result; + } + return removeRegionSamplingListener(listener); + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/include/gui/IRegionSamplingListener.h b/libs/gui/include/gui/IRegionSamplingListener.h new file mode 100644 index 0000000000..1803d9a1da --- /dev/null +++ b/libs/gui/include/gui/IRegionSamplingListener.h @@ -0,0 +1,43 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace android { + +class IRegionSamplingListener : public IInterface { +public: + DECLARE_META_INTERFACE(RegionSamplingListener) + + virtual void onSampleCollected(float medianLuma) = 0; +}; + +class BnRegionSamplingListener : public SafeBnInterface { +public: + BnRegionSamplingListener() + : SafeBnInterface("BnRegionSamplingListener") {} + + status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags = 0) override; +}; + +} // namespace android diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index a2db7bc4fa..1a0b6bbfdf 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -50,6 +50,7 @@ class HdrCapabilities; class IDisplayEventConnection; class IGraphicBufferProducer; class ISurfaceComposerClient; +class IRegionSamplingListener; class Rect; enum class FrameEvent; @@ -338,6 +339,26 @@ public: */ virtual status_t isWideColorDisplay(const sp& token, bool* outIsWideColorDisplay) const = 0; + + /* Registers a listener to stream median luma updates from SurfaceFlinger. + * + * The sampling area is bounded by both samplingArea and the given stopLayerHandle + * (i.e., only layers behind the stop layer will be captured and sampled). + * + * Multiple listeners may be provided so long as they have independent listeners. + * If multiple listeners are provided, the effective sampling region for each listener will + * be bounded by whichever stop layer has a lower Z value. + * + * Requires the same permissions as captureLayers and captureScreen. + */ + virtual status_t addRegionSamplingListener(const Rect& samplingArea, + const sp& stopLayerHandle, + const sp& listener) = 0; + + /* + * Removes a listener that was streaming median luma updates from SurfaceFlinger. + */ + virtual status_t removeRegionSamplingListener(const sp& listener) = 0; }; // ---------------------------------------------------------------------------- @@ -383,6 +404,8 @@ public: IS_WIDE_COLOR_DISPLAY, GET_DISPLAY_NATIVE_PRIMARIES, GET_PHYSICAL_DISPLAY_IDS, + ADD_REGION_SAMPLING_LISTENER, + REMOVE_REGION_SAMPLING_LISTENER, // Always append new enum to the end. }; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index bec9299456..f1278537e4 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -669,6 +669,16 @@ public: status_t isWideColorDisplay(const sp&, bool*) const override { return NO_ERROR; } + status_t addRegionSamplingListener(const Rect& /*samplingArea*/, + const sp& /*stopLayerHandle*/, + const sp& /*listener*/) override { + return NO_ERROR; + } + status_t removeRegionSamplingListener( + const sp& /*listener*/) override { + return NO_ERROR; + } + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 5f8de830e5..31c2153539 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1253,6 +1253,17 @@ status_t SurfaceFlinger::getCompositionPreference( return NO_ERROR; } +status_t SurfaceFlinger::addRegionSamplingListener( + const Rect& /*samplingArea*/, const sp& /*stopLayerHandle*/, + const sp& /*listener*/) { + return NO_ERROR; +} + +status_t SurfaceFlinger::removeRegionSamplingListener( + const sp& /*listener*/) { + return NO_ERROR; +} + // ---------------------------------------------------------------------------- sp SurfaceFlinger::createDisplayEventConnection( @@ -5016,7 +5027,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { return OK; } case CAPTURE_LAYERS: - case CAPTURE_SCREEN: { + case CAPTURE_SCREEN: + case ADD_REGION_SAMPLING_LISTENER: + case REMOVE_REGION_SAMPLING_LISTENER: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6546973411..08771310a7 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -471,7 +471,9 @@ private: status_t getProtectedContentSupport(bool* outSupported) const override; status_t isWideColorDisplay(const sp& displayToken, bool* outIsWideColorDisplay) const override; - + status_t addRegionSamplingListener(const Rect& samplingArea, const sp& stopLayerHandle, + const sp& listener) override; + status_t removeRegionSamplingListener(const sp& listener) override; /* ------------------------------------------------------------------------ * DeathRecipient interface */ -- cgit v1.2.3-59-g8ed1b From 5f21a5e4171a298e6b12131bf32743d8de095f10 Mon Sep 17 00:00:00 2001 From: chaviw Date: Thu, 14 Feb 2019 10:00:34 -0800 Subject: Add synchronous transaction to wait for setInputWindow to complete (1/n) Add SurfaceFlinger callback to notify when input windows have been set. The call to set input windows from SF to InputDispatcher is one way. Therefore, it won't wait to ensure the windows have been set. Add a callback method to allow InputDispatcher to notify SF when it's finished setting the input windows, allowing SF to block if needed. Bug: 123041491 Test: Builds and runs Change-Id: Ia4196d2e517c07d94ab9da71beab057d5d6fcf1c --- libs/gui/ISurfaceComposer.cpp | 11 +++++++++++ libs/gui/include/gui/ISurfaceComposer.h | 4 ++++ libs/gui/tests/Surface_test.cpp | 2 ++ services/surfaceflinger/SurfaceFlinger.cpp | 5 ++++- services/surfaceflinger/SurfaceFlinger.h | 1 + 5 files changed, 22 insertions(+), 1 deletion(-) (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index f77eeb246c..91972624a4 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -806,6 +806,12 @@ public: } return error; } + + virtual void setInputWindowsFinished() { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + remote()->transact(BnSurfaceComposer::SET_INPUT_WINDOWS_FINISHED, data, &reply); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1317,6 +1323,11 @@ status_t BnSurfaceComposer::onTransact( } return removeRegionSamplingListener(listener); } + case SET_INPUT_WINDOWS_FINISHED: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + setInputWindowsFinished(); + return NO_ERROR; + } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 1a0b6bbfdf..c2d7d28e52 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -359,6 +359,8 @@ public: * Removes a listener that was streaming median luma updates from SurfaceFlinger. */ virtual status_t removeRegionSamplingListener(const sp& listener) = 0; + + virtual void setInputWindowsFinished() = 0; }; // ---------------------------------------------------------------------------- @@ -406,6 +408,8 @@ public: GET_PHYSICAL_DISPLAY_IDS, ADD_REGION_SAMPLING_LISTENER, REMOVE_REGION_SAMPLING_LISTENER, + SET_INPUT_WINDOWS_FINISHED, + // Always append new enum to the end. }; diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index f1278537e4..8225647f90 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -679,6 +679,8 @@ public: return NO_ERROR; } + void setInputWindowsFinished() override {} + protected: IBinder* onAsBinder() override { return nullptr; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index dc3409b10b..a4f600504d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5154,7 +5154,8 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case GET_COLOR_MANAGEMENT: case GET_COMPOSITION_PREFERENCE: case GET_PROTECTED_CONTENT_SUPPORT: - case IS_WIDE_COLOR_DISPLAY: { + case IS_WIDE_COLOR_DISPLAY: + case SET_INPUT_WINDOWS_FINISHED: { return OK; } case CAPTURE_LAYERS: @@ -5887,6 +5888,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, return NO_ERROR; } +void SurfaceFlinger::setInputWindowsFinished() {} + // --------------------------------------------------------------------------- void SurfaceFlinger::State::traverseInZOrder(const LayerVector::Visitor& visitor) const { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 02898b21f0..2d53eb8573 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -479,6 +479,7 @@ private: status_t addRegionSamplingListener(const Rect& samplingArea, const sp& stopLayerHandle, const sp& listener) override; status_t removeRegionSamplingListener(const sp& listener) override; + void setInputWindowsFinished() override; /* ------------------------------------------------------------------------ * DeathRecipient interface */ -- cgit v1.2.3-59-g8ed1b From 291d88aa7a94790b85dfa633166bc0aa356cccb4 Mon Sep 17 00:00:00 2001 From: chaviw Date: Thu, 14 Feb 2019 10:33:58 -0800 Subject: Add synchronous transaction to wait for setInputWindow to complete (3/n) Added callback for InputDispatcher to report back to SF. Pass in an interface callback to setInputWindows so InputDispatcher can send a response when setInputWindows has completed. The callback can be null so InputDispatcher knows not to send a response on every setInputWindows call. Bug: 123041491 Test: Builds, runs Change-Id: I18b28141a0bb5f2e1ffb406d601dc7822ca89ecd --- include/input/IInputFlinger.h | 4 ++- include/input/ISetInputWindowsListener.h | 40 ++++++++++++++++++++++ libs/gui/ISurfaceComposer.cpp | 11 ------- libs/gui/include/gui/ISurfaceComposer.h | 3 -- libs/gui/include/gui/LayerState.h | 2 +- libs/gui/tests/Surface_test.cpp | 2 -- libs/input/Android.bp | 1 + libs/input/IInputFlinger.cpp | 9 +++-- libs/input/ISetInputWindowsListener.cpp | 53 ++++++++++++++++++++++++++++++ services/inputflinger/InputDispatcher.cpp | 6 +++- services/inputflinger/InputDispatcher.h | 8 +++-- services/inputflinger/InputManager.cpp | 5 +-- services/inputflinger/InputManager.h | 4 ++- services/inputflinger/host/InputFlinger.h | 3 +- services/surfaceflinger/SurfaceFlinger.cpp | 18 +++++++--- services/surfaceflinger/SurfaceFlinger.h | 14 +++++++- 16 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 include/input/ISetInputWindowsListener.h create mode 100644 libs/input/ISetInputWindowsListener.cpp (limited to 'libs/gui/ISurfaceComposer.cpp') diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h index ff443c6928..cd12fcd255 100644 --- a/include/input/IInputFlinger.h +++ b/include/input/IInputFlinger.h @@ -24,6 +24,7 @@ #include #include